use crate::wgpu::{self, TextureHandle, TextureViewHandle};
use std::ops::Deref;
use std::sync::Arc;
pub mod capturer;
pub mod image;
pub mod reshaper;
pub trait ToTextureView {
fn to_texture_view(&self) -> TextureView;
}
#[derive(Debug)]
pub struct Texture {
handle: Arc<TextureHandle>,
descriptor: wgpu::TextureDescriptor<'static>,
}
#[derive(Debug)]
pub struct TextureView {
handle: Arc<TextureViewHandle>,
descriptor: wgpu::TextureViewDescriptor,
texture_extent: wgpu::Extent3d,
texture_id: TextureId,
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct TextureId(usize);
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct TextureViewId(u64);
#[derive(Debug)]
pub struct Builder {
descriptor: wgpu::TextureDescriptor<'static>,
}
#[derive(Debug)]
pub struct ViewBuilder<'a> {
texture: &'a wgpu::Texture,
descriptor: wgpu::TextureViewDescriptor,
}
#[derive(Debug)]
pub struct BufferBytes {
buffer: wgpu::Buffer,
len_bytes: wgpu::BufferAddress,
}
impl Texture {
pub fn descriptor(&self) -> &wgpu::TextureDescriptor<'static> {
&self.descriptor
}
pub fn descriptor_cloned(&self) -> wgpu::TextureDescriptor<'static> {
wgpu::TextureDescriptor {
label: Some("nannou"),
size: self.extent(),
array_layer_count: self.array_layer_count(),
mip_level_count: self.mip_level_count(),
sample_count: self.sample_count(),
dimension: self.dimension(),
format: self.format(),
usage: self.usage(),
}
}
pub fn into_inner(self) -> Arc<TextureHandle> {
self.into()
}
pub fn inner(&self) -> &Arc<TextureHandle> {
&self.handle
}
pub fn size(&self) -> [u32; 2] {
[self.descriptor.size.width, self.descriptor.size.height]
}
pub fn extent(&self) -> wgpu::Extent3d {
self.descriptor.size
}
pub fn array_layer_count(&self) -> u32 {
self.descriptor.array_layer_count
}
pub fn mip_level_count(&self) -> u32 {
self.descriptor.mip_level_count
}
pub fn sample_count(&self) -> u32 {
self.descriptor.sample_count
}
pub fn dimension(&self) -> wgpu::TextureDimension {
self.descriptor.dimension
}
pub fn format(&self) -> wgpu::TextureFormat {
self.descriptor.format
}
pub fn usage(&self) -> wgpu::TextureUsage {
self.descriptor.usage
}
pub fn size_bytes(&self) -> usize {
data_size_bytes(&self.descriptor)
}
pub fn component_type(&self) -> wgpu::TextureComponentType {
format_to_component_type(self.format())
}
pub fn from_handle_and_descriptor(
handle: Arc<TextureHandle>,
descriptor: wgpu::TextureDescriptor<'static>,
) -> Self {
Texture { handle, descriptor }
}
pub fn id(&self) -> TextureId {
TextureId(Arc::into_raw(self.handle.clone()) as usize)
}
pub fn view(&self) -> ViewBuilder {
ViewBuilder {
texture: self,
descriptor: self.default_view_descriptor(),
}
}
pub fn view_dimension(&self) -> wgpu::TextureViewDimension {
match self.dimension() {
wgpu::TextureDimension::D1 => wgpu::TextureViewDimension::D1,
wgpu::TextureDimension::D2 => match self.array_layer_count() {
1 => wgpu::TextureViewDimension::D2,
_ => wgpu::TextureViewDimension::D2Array,
},
wgpu::TextureDimension::D3 => wgpu::TextureViewDimension::D3,
}
}
pub fn default_view_descriptor(&self) -> wgpu::TextureViewDescriptor {
let dimension = self.view_dimension();
let aspect = wgpu::TextureAspect::All;
wgpu::TextureViewDescriptor {
format: self.format(),
dimension,
aspect,
base_mip_level: 0,
level_count: self.mip_level_count(),
base_array_layer: 0,
array_layer_count: self.array_layer_count(),
}
}
pub fn default_copy_view(&self) -> wgpu::TextureCopyView {
wgpu::TextureCopyView {
texture: &self.handle,
mip_level: 0,
array_layer: 0,
origin: wgpu::Origin3d::ZERO,
}
}
pub fn default_buffer_copy_view<'a>(
&self,
buffer: &'a wgpu::Buffer,
) -> wgpu::BufferCopyView<'a> {
let format_size_bytes = format_size_bytes(self.format());
let [width, height] = self.size();
wgpu::BufferCopyView {
buffer,
offset: 0,
bytes_per_row: width * format_size_bytes,
rows_per_image: height,
}
}
pub fn upload_data(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
data: &[u8],
) {
let texture_size_bytes = self.size_bytes();
assert_eq!(data.len(), texture_size_bytes);
let buffer = device.create_buffer_with_data(data, wgpu::BufferUsage::COPY_SRC);
let buffer_copy_view = self.default_buffer_copy_view(&buffer);
let texture_copy_view = self.default_copy_view();
let extent = self.extent();
encoder.copy_buffer_to_texture(buffer_copy_view, texture_copy_view, extent);
}
pub fn to_buffer(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
) -> (wgpu::Buffer, wgpu::BufferAddress) {
fn texture_to_buffer(
texture: &wgpu::Texture,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
) -> (wgpu::Buffer, wgpu::BufferAddress) {
let size = texture.extent();
let format = texture.format();
let format_size_bytes = format_size_bytes(format) as u64;
let layer_len_pixels = size.width as u64 * size.height as u64 * size.depth as u64;
let layer_size_bytes = layer_len_pixels * format_size_bytes;
let data_size_bytes = layer_size_bytes * texture.array_layer_count() as u64;
let buffer_descriptor = wgpu::BufferDescriptor {
label: Some("nannou_texture_to_buffer"),
size: data_size_bytes,
usage: wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::MAP_READ,
};
let buffer = device.create_buffer(&buffer_descriptor);
let texture_copy_view = texture.default_copy_view();
let buffer_copy_view = texture.default_buffer_copy_view(&buffer);
encoder.copy_texture_to_buffer(texture_copy_view, buffer_copy_view, size);
(buffer, data_size_bytes)
}
if self.sample_count() > 1 {
let view = self.create_default_view();
let descriptor = self.descriptor_cloned();
let resolved_texture = wgpu::TextureBuilder::from(descriptor)
.sample_count(1)
.usage(wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::COPY_SRC)
.build(device);
let resolved_view = resolved_texture.create_default_view();
wgpu::resolve_texture(&view, &resolved_view, encoder);
texture_to_buffer(&resolved_texture, device, encoder)
} else {
texture_to_buffer(self, device, encoder)
}
}
pub fn to_buffer_bytes(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
) -> BufferBytes {
let (buffer, len_bytes) = self.to_buffer(device, encoder);
BufferBytes { buffer, len_bytes }
}
}
impl TextureView {
pub fn descriptor(&self) -> &wgpu::TextureViewDescriptor {
&self.descriptor
}
pub fn descriptor_cloned(&self) -> wgpu::TextureViewDescriptor {
wgpu::TextureViewDescriptor {
format: self.format(),
dimension: self.dimension(),
aspect: self.aspect(),
base_mip_level: self.base_mip_level(),
level_count: self.level_count(),
base_array_layer: self.base_array_layer(),
array_layer_count: self.array_layer_count(),
}
}
pub fn format(&self) -> wgpu::TextureFormat {
self.descriptor.format
}
pub fn dimension(&self) -> wgpu::TextureViewDimension {
self.descriptor.dimension
}
pub fn aspect(&self) -> wgpu::TextureAspect {
self.descriptor.aspect
}
pub fn base_mip_level(&self) -> u32 {
self.descriptor.base_mip_level
}
pub fn level_count(&self) -> u32 {
self.descriptor.level_count
}
pub fn base_array_layer(&self) -> u32 {
self.descriptor.base_array_layer
}
pub fn array_layer_count(&self) -> u32 {
self.descriptor.array_layer_count
}
pub fn component_type(&self) -> wgpu::TextureComponentType {
format_to_component_type(self.format())
}
pub fn id(&self) -> TextureViewId {
texture_view_id(&self.texture_id, &self.descriptor)
}
pub fn size(&self) -> [u32; 2] {
[self.texture_extent.width, self.texture_extent.height]
}
pub fn extent(&self) -> wgpu::Extent3d {
self.texture_extent.clone()
}
pub fn texture_id(&self) -> TextureId {
self.texture_id
}
pub fn inner(&self) -> &Arc<wgpu::TextureViewHandle> {
&self.handle
}
pub fn into_inner(self) -> Arc<wgpu::TextureViewHandle> {
self.handle
}
}
impl Builder {
pub const DEFAULT_SIDE: u32 = 128;
pub const DEFAULT_DEPTH: u32 = 1;
pub const DEFAULT_SIZE: wgpu::Extent3d = wgpu::Extent3d {
width: Self::DEFAULT_SIDE,
height: Self::DEFAULT_SIDE,
depth: Self::DEFAULT_DEPTH,
};
pub const DEFAULT_ARRAY_LAYER_COUNT: u32 = 1;
pub const DEFAULT_MIP_LEVEL_COUNT: u32 = 1;
pub const DEFAULT_SAMPLE_COUNT: u32 = 1;
pub const DEFAULT_DIMENSION: wgpu::TextureDimension = wgpu::TextureDimension::D2;
pub const DEFAULT_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
pub const DEFAULT_USAGE: wgpu::TextureUsage = wgpu::TextureUsage::ORDERED;
pub const DEFAULT_DESCRIPTOR: wgpu::TextureDescriptor<'static> = wgpu::TextureDescriptor {
label: Some("nannou_texture_descriptor"),
size: Self::DEFAULT_SIZE,
array_layer_count: Self::DEFAULT_ARRAY_LAYER_COUNT,
mip_level_count: Self::DEFAULT_MIP_LEVEL_COUNT,
sample_count: Self::DEFAULT_SAMPLE_COUNT,
dimension: Self::DEFAULT_DIMENSION,
format: Self::DEFAULT_FORMAT,
usage: Self::DEFAULT_USAGE,
};
pub fn new() -> Self {
Self::default()
}
pub fn size(mut self, [width, height]: [u32; 2]) -> Self {
self.descriptor.size.width = width;
self.descriptor.size.height = height;
self.infer_dimension_from_size();
self
}
pub fn depth(mut self, depth: u32) -> Self {
self.descriptor.size.depth = depth;
self.infer_dimension_from_size();
self
}
pub fn extent(mut self, extent: wgpu::Extent3d) -> Self {
self.descriptor.size = extent;
self.infer_dimension_from_size();
self
}
pub fn array_layer_count(mut self, count: u32) -> Self {
self.descriptor.array_layer_count = count;
self
}
pub fn mip_level_count(mut self, count: u32) -> Self {
self.descriptor.mip_level_count = count;
self
}
pub fn sample_count(mut self, count: u32) -> Self {
self.descriptor.sample_count = count;
self
}
pub fn format(mut self, format: wgpu::TextureFormat) -> Self {
self.descriptor.format = format;
self
}
pub fn usage(mut self, usage: wgpu::TextureUsage) -> Self {
self.descriptor.usage = usage;
self
}
fn infer_dimension_from_size(&mut self) {
if self.descriptor.size.depth > 1 {
self.descriptor.dimension = wgpu::TextureDimension::D3;
} else if self.descriptor.size.height > 1 {
self.descriptor.dimension = wgpu::TextureDimension::D2;
} else {
self.descriptor.dimension = wgpu::TextureDimension::D1;
}
}
pub fn build(self, device: &wgpu::Device) -> Texture {
let handle = Arc::new(device.create_texture(&self.descriptor));
let descriptor = self.into();
Texture { handle, descriptor }
}
pub fn into_descriptor(self) -> wgpu::TextureDescriptor<'static> {
self.into()
}
}
impl<'a> ViewBuilder<'a> {
pub fn format(mut self, format: wgpu::TextureFormat) -> Self {
self.descriptor.format = format;
self
}
pub fn dimension(mut self, dimension: wgpu::TextureViewDimension) -> Self {
self.descriptor.dimension = dimension;
self
}
pub fn aspect(mut self, aspect: wgpu::TextureAspect) -> Self {
self.descriptor.aspect = aspect;
self
}
pub fn level_count(mut self, level_count: u32) -> Self {
self.descriptor.level_count = level_count;
self
}
pub fn base_array_layer(mut self, base_array_layer: u32) -> Self {
self.descriptor.base_array_layer = base_array_layer;
self
}
pub fn array_layer_count(mut self, array_layer_count: u32) -> Self {
self.descriptor.array_layer_count = array_layer_count;
self
}
pub fn layer(self, layer: u32) -> Self {
self.base_array_layer(layer).array_layer_count(1)
}
pub fn build(self) -> TextureView {
TextureView {
handle: Arc::new(self.texture.inner().create_view(&self.descriptor)),
descriptor: self.descriptor,
texture_id: self.texture.id(),
texture_extent: self.texture.extent(),
}
}
pub fn into_descriptor(self) -> wgpu::TextureViewDescriptor {
self.into()
}
}
impl BufferBytes {
pub async fn read(&self) -> Result<wgpu::BufferReadMapping, wgpu::BufferAsyncErr> {
self.buffer.map_read(0, self.len_bytes).await
}
pub fn len_bytes(&self) -> wgpu::BufferAddress {
self.len_bytes
}
pub fn inner(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn into_inner(self) -> wgpu::Buffer {
self.buffer
}
}
impl<'a, T> ToTextureView for &'a T
where
T: ToTextureView,
{
fn to_texture_view(&self) -> TextureView {
(**self).to_texture_view()
}
}
impl<'a, T> ToTextureView for &'a mut T
where
T: ToTextureView,
{
fn to_texture_view(&self) -> TextureView {
(**self).to_texture_view()
}
}
impl ToTextureView for TextureView {
fn to_texture_view(&self) -> TextureView {
self.clone()
}
}
impl ToTextureView for Texture {
fn to_texture_view(&self) -> TextureView {
self.view().build()
}
}
impl Clone for TextureView {
fn clone(&self) -> Self {
TextureView {
handle: self.handle.clone(),
descriptor: self.descriptor_cloned(),
texture_id: self.texture_id(),
texture_extent: self.extent(),
}
}
}
impl Clone for Texture {
fn clone(&self) -> Self {
let handle = self.handle.clone();
let descriptor = self.descriptor_cloned();
Self { handle, descriptor }
}
}
impl Deref for Texture {
type Target = TextureHandle;
fn deref(&self) -> &Self::Target {
&*self.handle
}
}
impl Deref for TextureView {
type Target = TextureViewHandle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl Into<Arc<TextureHandle>> for Texture {
fn into(self) -> Arc<TextureHandle> {
self.handle
}
}
impl Default for Builder {
fn default() -> Self {
Self {
descriptor: Self::DEFAULT_DESCRIPTOR,
}
}
}
impl From<wgpu::TextureDescriptor<'static>> for Builder {
fn from(descriptor: wgpu::TextureDescriptor<'static>) -> Self {
Self { descriptor }
}
}
impl Into<wgpu::TextureDescriptor<'static>> for Builder {
fn into(self) -> wgpu::TextureDescriptor<'static> {
self.descriptor
}
}
impl<'a> Into<wgpu::TextureViewDescriptor> for ViewBuilder<'a> {
fn into(self) -> wgpu::TextureViewDescriptor {
self.descriptor
}
}
fn texture_view_id(texture_id: &TextureId, desc: &wgpu::TextureViewDescriptor) -> TextureViewId {
use std::hash::{Hash, Hasher};
let mut s = std::collections::hash_map::DefaultHasher::new();
texture_id.hash(&mut s);
desc.format.hash(&mut s);
desc.dimension.hash(&mut s);
desc.aspect.hash(&mut s);
desc.base_mip_level.hash(&mut s);
desc.level_count.hash(&mut s);
desc.base_array_layer.hash(&mut s);
desc.array_layer_count.hash(&mut s);
TextureViewId(s.finish())
}
pub fn data_size_bytes(desc: &wgpu::TextureDescriptor) -> usize {
desc.size.width as usize
* desc.size.height as usize
* desc.size.depth as usize
* desc.array_layer_count as usize
* format_size_bytes(desc.format) as usize
}
pub fn format_size_bytes(format: wgpu::TextureFormat) -> u32 {
use crate::wgpu::TextureFormat::*;
match format {
R8Unorm | R8Snorm | R8Uint | R8Sint => 1,
R16Uint | R16Sint | R16Float | Rg8Unorm | Rg8Snorm | Rg8Uint | Rg8Sint => 2,
R32Uint | R32Sint | R32Float | Rg16Uint | Rg16Sint | Rg16Float | Rgba8Unorm
| Rgba8UnormSrgb | Rgba8Snorm | Rgba8Uint | Rgba8Sint | Bgra8Unorm | Bgra8UnormSrgb
| Rgb10a2Unorm | Rg11b10Float => 4,
Rg32Uint | Rg32Sint | Rg32Float | Rgba16Uint | Rgba16Sint | Rgba16Float | Rgba32Uint
| Rgba32Sint | Rgba32Float => 8,
Depth32Float | Depth24Plus | Depth24PlusStencil8 => 4,
}
}
pub fn extent_3d_eq(a: &wgpu::Extent3d, b: &wgpu::Extent3d) -> bool {
a.width == b.width && a.height == b.height && a.depth == b.depth
}
pub fn descriptor_eq(a: &wgpu::TextureDescriptor, b: &wgpu::TextureDescriptor) -> bool {
extent_3d_eq(&a.size, &b.size)
&& a.array_layer_count == b.array_layer_count
&& a.mip_level_count == b.mip_level_count
&& a.sample_count == b.sample_count
&& a.dimension == b.dimension
&& a.format == b.format
&& a.usage == b.usage
}
pub fn format_to_component_type(format: wgpu::TextureFormat) -> wgpu::TextureComponentType {
match format {
wgpu::TextureFormat::R8Uint
| wgpu::TextureFormat::R16Uint
| wgpu::TextureFormat::Rg8Uint
| wgpu::TextureFormat::R32Uint
| wgpu::TextureFormat::Rg16Uint
| wgpu::TextureFormat::Rgba8Uint
| wgpu::TextureFormat::Rg32Uint
| wgpu::TextureFormat::Rgba16Uint
| wgpu::TextureFormat::Rgba32Uint => wgpu::TextureComponentType::Uint,
wgpu::TextureFormat::R8Sint
| wgpu::TextureFormat::R16Sint
| wgpu::TextureFormat::Rg8Sint
| wgpu::TextureFormat::R32Sint
| wgpu::TextureFormat::Rg16Sint
| wgpu::TextureFormat::Rgba8Sint
| wgpu::TextureFormat::Rg32Sint
| wgpu::TextureFormat::Rgba16Sint
| wgpu::TextureFormat::Rgba32Sint => wgpu::TextureComponentType::Sint,
wgpu::TextureFormat::R8Unorm
| wgpu::TextureFormat::R8Snorm
| wgpu::TextureFormat::R16Float
| wgpu::TextureFormat::R32Float
| wgpu::TextureFormat::Rg8Unorm
| wgpu::TextureFormat::Rg8Snorm
| wgpu::TextureFormat::Rg16Float
| wgpu::TextureFormat::Rg11b10Float
| wgpu::TextureFormat::Rg32Float
| wgpu::TextureFormat::Rgba8Snorm
| wgpu::TextureFormat::Rgba16Float
| wgpu::TextureFormat::Rgba32Float
| wgpu::TextureFormat::Rgba8Unorm
| wgpu::TextureFormat::Rgba8UnormSrgb
| wgpu::TextureFormat::Bgra8Unorm
| wgpu::TextureFormat::Bgra8UnormSrgb
| wgpu::TextureFormat::Rgb10a2Unorm
| wgpu::TextureFormat::Depth32Float
| wgpu::TextureFormat::Depth24Plus
| wgpu::TextureFormat::Depth24PlusStencil8 => wgpu::TextureComponentType::Float,
}
}