use crate::{self as wgpu, RowPaddedBuffer, TextureHandle, TextureViewHandle};
use std::ops::Deref;
use std::sync::Arc;
#[cfg(feature = "capturer")]
pub mod capturer;
#[cfg(feature = "image")]
pub mod image;
pub mod reshaper;
pub mod row_padded_buffer;
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>,
info: TextureViewInfo,
texture_extent: wgpu::Extent3d,
texture_id: TextureId,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct TextureViewInfo {
pub label: &'static str,
pub format: wgpu::TextureFormat,
pub dimension: wgpu::TextureViewDimension,
pub aspect: wgpu::TextureAspect,
pub base_mip_level: u32,
pub level_count: Option<u32>,
pub base_array_layer: u32,
pub array_layer_count: Option<u32>,
}
#[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,
info: TextureViewInfo,
}
impl Texture {
pub fn descriptor(&self) -> &wgpu::TextureDescriptor<'static> {
&self.descriptor
}
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 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::TextureUsages {
self.descriptor.usage
}
pub fn size_bytes(&self) -> usize {
data_size_bytes(&self.descriptor)
}
pub fn sample_type(&self) -> wgpu::TextureSampleType {
self.format()
.sample_type(None)
.expect("Expected the format to have a sample type")
}
pub fn from_handle_and_descriptor(
handle: Arc<TextureHandle>,
descriptor: wgpu::TextureDescriptor<'static>,
) -> Self {
Texture { handle, descriptor }
}
pub fn id(&self) -> TextureId {
TextureId(Arc::as_ptr(&self.handle) as usize)
}
pub fn view(&self) -> ViewBuilder {
ViewBuilder {
texture: self,
info: self.default_view_info(),
}
}
pub fn view_dimension(&self) -> wgpu::TextureViewDimension {
match self.dimension() {
wgpu::TextureDimension::D1 => wgpu::TextureViewDimension::D1,
wgpu::TextureDimension::D2 => match self.descriptor.size.depth_or_array_layers {
1 => wgpu::TextureViewDimension::D2,
_ => wgpu::TextureViewDimension::D2Array,
},
wgpu::TextureDimension::D3 => wgpu::TextureViewDimension::D3,
}
}
pub fn default_view_info(&self) -> TextureViewInfo {
let format = self.format();
TextureViewInfo {
label: TextureView::DEFAULT_LABEL,
format: format,
dimension: self.view_dimension(),
aspect: infer_aspect_from_format(format),
base_mip_level: 0,
level_count: Some(self.mip_level_count()),
base_array_layer: 0,
array_layer_count: Some(1),
}
}
pub fn default_view_descriptor(&self) -> wgpu::TextureViewDescriptor<'static> {
view_info_to_view_descriptor(&self.default_view_info())
}
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 = wgpu::RowPaddedBuffer::for_texture(
device,
self,
wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::MAP_WRITE,
);
buffer.write(data);
buffer.encode_copy_into(encoder, self);
}
pub fn to_buffer(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
) -> wgpu::RowPaddedBuffer {
assert_eq!(
self.extent().depth_or_array_layers,
1,
"cannot convert a 3d texture to a RowPaddedBuffer"
);
if self.sample_count() > 1 {
let view = self.create_view(&wgpu::TextureViewDescriptor::default());
let descriptor = self.descriptor.clone();
let resolved_texture = wgpu::TextureBuilder::from(descriptor)
.sample_count(1)
.usage(wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC)
.build(device);
let resolved_view =
resolved_texture.create_view(&wgpu::TextureViewDescriptor::default());
wgpu::resolve_texture(&view, &resolved_view, encoder);
let buffer = RowPaddedBuffer::for_texture(
device,
&resolved_texture,
wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
);
buffer.encode_copy_from(encoder, &resolved_texture);
buffer
} else {
let buffer = RowPaddedBuffer::for_texture(
device,
self,
wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
);
buffer.encode_copy_from(encoder, self);
buffer
}
}
}
impl TextureViewInfo {
pub fn descriptor(&self) -> wgpu::TextureViewDescriptor<'static> {
view_info_to_view_descriptor(self)
}
}
impl TextureView {
pub const DEFAULT_LABEL: &'static str = "nannou-texture-view";
pub fn info(&self) -> &TextureViewInfo {
&self.info
}
pub fn descriptor(&self) -> wgpu::TextureViewDescriptor<'static> {
self.info.descriptor()
}
pub fn format(&self) -> wgpu::TextureFormat {
self.info.format
}
pub fn dimension(&self) -> wgpu::TextureViewDimension {
self.info.dimension
}
pub fn aspect(&self) -> wgpu::TextureAspect {
self.info.aspect
}
pub fn base_mip_level(&self) -> u32 {
self.info.base_mip_level
}
pub fn level_count(&self) -> Option<u32> {
self.info.level_count
}
pub fn base_array_layer(&self) -> u32 {
self.info.base_array_layer
}
pub fn array_layer_count(&self) -> Option<u32> {
self.info.array_layer_count
}
pub fn sample_type(&self) -> wgpu::TextureSampleType {
self.format()
.sample_type(None)
.expect("Expected the format to have a sample type")
}
pub fn id(&self) -> TextureViewId {
texture_view_id(&self.texture_id, &self.info)
}
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_or_array_layers: 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::TextureUsages = wgpu::TextureUsages::all(); pub const DEFAULT_DESCRIPTOR: wgpu::TextureDescriptor<'static> = wgpu::TextureDescriptor {
label: Some("nannou Texture"),
size: Self::DEFAULT_SIZE,
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,
view_formats: &[],
};
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_or_array_layers = 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 dimension(mut self, dimension: wgpu::TextureDimension) -> Self {
self.descriptor.dimension = dimension;
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::TextureUsages) -> Self {
self.descriptor.usage = usage;
self
}
fn infer_dimension_from_size(&mut self) {
if self.descriptor.size.depth_or_array_layers > 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 label(mut self, label: &'static str) -> Self {
self.info.label = label;
self
}
pub fn format(mut self, format: wgpu::TextureFormat) -> Self {
self.info.format = format;
self
}
pub fn dimension(mut self, dimension: wgpu::TextureViewDimension) -> Self {
self.info.dimension = dimension;
self
}
pub fn aspect(mut self, aspect: wgpu::TextureAspect) -> Self {
self.info.aspect = aspect;
self
}
pub fn level_count(mut self, level_count: Option<u32>) -> Self {
self.info.level_count = level_count;
self
}
pub fn base_array_layer(mut self, base_array_layer: u32) -> Self {
self.info.base_array_layer = base_array_layer;
self
}
pub fn array_layer_count(mut self, array_layer_count: Option<u32>) -> Self {
match (self.info.dimension, array_layer_count) {
(wgpu::TextureViewDimension::D2Array, Some(1)) => {
self.info.dimension = wgpu::TextureViewDimension::D2;
}
_ => (),
}
self.info.array_layer_count = array_layer_count;
self
}
pub fn layer(self, layer: u32) -> Self {
self.base_array_layer(layer).array_layer_count(Some(1))
}
pub fn build(self) -> TextureView {
let descriptor = self.info.descriptor();
TextureView {
handle: Arc::new(self.texture.inner().create_view(&descriptor)),
info: self.info,
texture_id: self.texture.id(),
texture_extent: self.texture.extent(),
}
}
pub fn into_descriptor(self) -> wgpu::TextureViewDescriptor<'static> {
self.info.descriptor()
}
}
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(),
info: self.info.clone(),
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.clone();
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 Default for Builder {
fn default() -> Self {
Self {
descriptor: Self::DEFAULT_DESCRIPTOR,
}
}
}
impl From<Texture> for Arc<TextureHandle> {
fn from(t: Texture) -> Self {
t.handle
}
}
impl From<TextureViewInfo> for wgpu::TextureViewDescriptor<'static> {
fn from(info: TextureViewInfo) -> Self {
view_info_to_view_descriptor(&info)
}
}
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> From<ViewBuilder<'a>> for TextureViewInfo {
fn from(builder: ViewBuilder<'a>) -> Self {
builder.info
}
}
fn texture_view_id(texture_id: &TextureId, view_info: &TextureViewInfo) -> TextureViewId {
use std::hash::{Hash, Hasher};
let mut s = std::collections::hash_map::DefaultHasher::new();
texture_id.hash(&mut s);
view_info.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_or_array_layers as usize
* format_size_bytes(desc.format) as usize
}
pub fn format_size_bytes(format: wgpu::TextureFormat) -> u32 {
format
.block_size(None)
.expect("Expected the format to have a block size") as u32
}
pub fn extent_3d_eq(a: &wgpu::Extent3d, b: &wgpu::Extent3d) -> bool {
a.width == b.width && a.height == b.height && a.depth_or_array_layers == b.depth_or_array_layers
}
pub fn descriptor_eq(a: &wgpu::TextureDescriptor, b: &wgpu::TextureDescriptor) -> bool {
extent_3d_eq(&a.size, &b.size)
&& 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 infer_aspect_from_format(format: wgpu::TextureFormat) -> wgpu::TextureAspect {
use wgpu::TextureFormat::*;
match format {
Depth32Float | Depth24Plus => wgpu::TextureAspect::DepthOnly,
_ => wgpu::TextureAspect::All,
}
}
fn view_info_to_view_descriptor(info: &TextureViewInfo) -> wgpu::TextureViewDescriptor<'static> {
wgpu::TextureViewDescriptor {
label: Some(info.label),
format: Some(info.format),
dimension: Some(info.dimension),
aspect: info.aspect,
base_mip_level: info.base_mip_level,
mip_level_count: info.level_count,
base_array_layer: info.base_array_layer,
array_layer_count: info.array_layer_count,
}
}