use __gl;
use __gl::types::{GLenum, GLuint};
use std::ops::Range;
use debug::{Object, ObjectType};
use device::Device;
use error::Result;
use format::{BaseFormat, Format, FormatLayout};
use {Extent, Offset};
pub struct Image {
raw: GLuint,
target: GLenum,
}
impl Object for Image {
const TYPE: ObjectType = ObjectType::Image;
fn handle(&self) -> GLuint {
self.raw
}
}
pub enum ImageType {
D1 {
width: u32,
layers: u32,
},
D2 {
width: u32,
height: u32,
layers: u32,
samples: u32,
},
D3 {
width: u32,
height: u32,
depth: u32,
},
}
#[repr(transparent)]
pub struct ImageView(pub(crate) GLuint);
pub enum ImageViewType {
D1,
D2,
D3,
Cube,
D1Array,
D2Array,
CubeArray,
}
pub struct SubresourceRange {
pub levels: Range<u32>,
pub layers: Range<u32>,
}
pub struct SubresourceLevel {
pub level: u32,
pub layers: Range<u32>,
}
pub struct SubresourceLayout {
pub base_format: BaseFormat,
pub format_layout: FormatLayout,
pub row_pitch: u32,
pub image_height: u32,
pub alignment: u32,
}
impl Device {
pub fn create_image(&self, ty: ImageType, format: Format, levels: u32) -> Result<Image> {
let target = match ty {
ImageType::D1 { layers: 1, .. } => __gl::TEXTURE_1D,
ImageType::D1 { .. } => __gl::TEXTURE_1D_ARRAY,
ImageType::D2 {
layers: 1,
samples: 1,
..
} => __gl::TEXTURE_2D,
ImageType::D2 {
layers: 6,
samples: 1,
..
} => __gl::TEXTURE_CUBE_MAP,
ImageType::D2 {
layers, samples: 1, ..
} if layers % 6 == 0 => __gl::TEXTURE_CUBE_MAP_ARRAY,
ImageType::D2 { samples: 1, .. } => __gl::TEXTURE_2D_ARRAY,
ImageType::D2 { layers: 1, .. } => __gl::TEXTURE_2D_MULTISAMPLE,
ImageType::D2 { .. } => __gl::TEXTURE_2D_MULTISAMPLE_ARRAY,
ImageType::D3 { .. } => __gl::TEXTURE_3D,
};
let mut image = 0;
unsafe {
self.0.CreateTextures(target, 1, &mut image);
}
self.get_error()?;
match ty {
ImageType::D1 { width, layers: 1 } => unsafe {
self.0
.TextureStorage1D(image, levels as _, format as _, width as _);
},
ImageType::D1 {
width,
layers: height,
}
| ImageType::D2 {
width,
height,
layers: 1,
samples: 1,
}
| ImageType::D2 {
width,
height,
layers: 6,
samples: 1,
} => unsafe {
self.0
.TextureStorage2D(image, levels as _, format as _, width as _, height as _);
},
ImageType::D2 {
width,
height,
layers: depth,
samples: 1,
}
| ImageType::D3 {
width,
height,
depth,
} => unsafe {
self.0.TextureStorage3D(
image,
levels as _,
format as _,
width as _,
height as _,
depth as _,
);
},
_ => unimplemented!(),
}
self.get_error()?;
Ok(Image { raw: image, target })
}
pub fn delete_image(&self, image: Image) {
self.delete_images(&[image]);
}
pub fn delete_images(&self, images: &[Image]) {
let images = images.iter().map(|i| i.raw).collect::<Vec<_>>();
unsafe {
self.0
.DeleteTextures(images.len() as _, images.as_ptr() as *const _);
}
}
pub fn copy_host_to_image<T>(
&self,
image: &Image,
subresource: SubresourceLevel,
offset: Offset,
extent: Extent,
data: &[T],
layout: SubresourceLayout,
) {
unsafe {
self.0
.PixelStorei(__gl::UNPACK_ALIGNMENT, layout.alignment as _)
};
match image.target {
__gl::TEXTURE_2D if subresource.layers == (0..1) => unsafe {
self.0.TextureSubImage2D(
image.raw,
subresource.level as _,
offset.x,
offset.y,
extent.width as _,
extent.height as _,
layout.base_format as _,
layout.format_layout as _,
data.as_ptr() as *const _,
)
},
_ => unimplemented!(),
}
}
pub fn create_image_view(
&self,
image: &Image,
ty: ImageViewType,
format: Format,
range: SubresourceRange,
) -> Result<ImageView> {
let target = match ty {
ImageViewType::D1 => __gl::TEXTURE_1D,
ImageViewType::D2 if image.target == __gl::TEXTURE_2D_MULTISAMPLE => {
__gl::TEXTURE_2D_MULTISAMPLE
}
ImageViewType::D2 => __gl::TEXTURE_2D,
ImageViewType::D3 => __gl::TEXTURE_3D,
ImageViewType::Cube => __gl::TEXTURE_CUBE_MAP,
ImageViewType::D1Array => __gl::TEXTURE_1D_ARRAY,
ImageViewType::D2Array if image.target == __gl::TEXTURE_2D_MULTISAMPLE_ARRAY => {
__gl::TEXTURE_2D_MULTISAMPLE_ARRAY
}
ImageViewType::D2Array => __gl::TEXTURE_2D_ARRAY,
ImageViewType::CubeArray => __gl::TEXTURE_CUBE_MAP_ARRAY,
};
let mut view = 0;
unsafe {
self.0.GenTextures(1, &mut view);
}
self.get_error()?;
unsafe {
self.0.TextureView(
view,
target,
image.raw,
format as _,
range.levels.start,
range.levels.end - range.levels.start,
range.layers.start,
range.layers.end - range.layers.start,
);
}
self.get_error()?;
Ok(ImageView(view))
}
pub fn delete_image_view(&self, view: ImageView) {
self.delete_image_views(&[view]);
}
pub fn delete_image_views(&self, views: &[ImageView]) {
unsafe {
self.0.DeleteTextures(
views.len() as _,
views.as_ptr() as *const _,
);
}
}
pub fn bind_image_views(&self, first: u32, views: &[&ImageView]) {
let views = views.iter().map(|view| view.0).collect::<Vec<_>>();
unsafe {
self.0.BindTextures(first, views.len() as _, views.as_ptr());
}
}
pub fn generate_mipmaps(&self, image: &Image) {
unsafe {
self.0.GenerateTextureMipmap(image.raw);
}
}
}