use std::error::Error;
use std::{fmt, cmp, hash};
use memory::{Bind, Usage};
use {format, state, target, Resources};
pub use target::{Layer, Level};
pub const MAX_LEVEL: Level = 15;
#[derive(Debug)]
pub struct Raw<R: Resources> {
resource: R::Texture,
info: Info,
}
impl<R: Resources> Raw<R> {
#[doc(hidden)]
pub fn new(resource: R::Texture, info: Info) -> Self {
Raw {
resource: resource,
info: info,
}
}
#[doc(hidden)]
pub fn resource(&self) -> &R::Texture { &self.resource }
pub fn get_info(&self) -> &Info { &self.info }
}
impl<R: Resources + cmp::PartialEq> cmp::PartialEq for Raw<R> {
fn eq(&self, other: &Self) -> bool {
self.resource().eq(other.resource())
}
}
impl<R: Resources + cmp::Eq> cmp::Eq for Raw<R> {}
impl<R: Resources + hash::Hash> hash::Hash for Raw<R> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.resource().hash(state);
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CreationError {
Format(format::SurfaceType, Option<format::ChannelType>),
Kind,
Samples(AaMode),
Size(Size),
Data(usize),
Usage(Usage),
Mipmap,
Level(Level),
}
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CreationError::Format(surf, chan) => write!(f, "{}: ({:?}, {:?})",
self.description(), surf, chan),
CreationError::Samples(aa) => write!(f, "{}: {:?}", self.description(), aa),
CreationError::Size(size) => write!(f, "{}: {}", self.description(), size),
CreationError::Data(data) => write!(f, "{}: {}", self.description(), data),
CreationError::Usage(usage) => write!(f, "{}: {:?}", self.description(), usage),
_ => write!(f, "{}", self.description()),
}
}
}
impl Error for CreationError {
fn description(&self) -> &str {
match *self {
CreationError::Format(..) => "Failed to map a given format to the device",
CreationError::Kind => "The kind doesn't support a particular operation",
CreationError::Samples(_) => "Failed to map a given multisampled kind to the device",
CreationError::Size(_) => "Unsupported size in one of the dimensions",
CreationError::Data(_) => "The given data has a different size than the target texture slice",
CreationError::Usage(_) => "The expected texture usage mode is not supported by a graphic API",
CreationError::Mipmap => "The requested mipmap creation parameter is unsupported",
CreationError::Level(_) => "The requested mipmap level count does not match the provided data",
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LayerError {
NotExpected(Kind),
OutOfBounds(target::Layer, target::Layer),
}
impl fmt::Display for LayerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LayerError::NotExpected(kind) => write!(f, "{}: {:?}", self.description(), kind),
LayerError::OutOfBounds(layer, count) => write!(f, "{}: {}/{}", self.description(), layer, count),
}
}
}
impl Error for LayerError {
fn description(&self) -> &str {
match *self {
LayerError::NotExpected(_) => "The source texture kind doesn't support array slices",
LayerError::OutOfBounds(_, _) => "Selected layer is outside of the provided range",
}
}
}
pub type Size = u16;
pub type Bits = u8;
pub type NumSamples = u8;
pub type NumFragments = u8;
pub type Dimensions = (Size, Size, Size, AaMode);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum AaMode {
Single,
Multi(NumSamples),
Coverage(NumSamples, NumFragments),
}
impl From<NumSamples> for AaMode {
fn from(ns: NumSamples) -> AaMode {
if ns > 1 {
AaMode::Multi(ns)
} else {
AaMode::Single
}
}
}
impl AaMode {
pub fn get_num_fragments(&self) -> NumFragments {
match *self {
AaMode::Single => 1,
AaMode::Multi(n) => n,
AaMode::Coverage(_, nf) => nf,
}
}
pub fn needs_resolve(&self) -> bool {
self.get_num_fragments() > 1
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum FilterMethod {
Scale,
Mipmap,
Bilinear,
Trilinear,
Anisotropic(u8)
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum CubeFace {
PosX,
NegX,
PosY,
NegY,
PosZ,
NegZ,
}
pub const CUBE_FACES: [CubeFace; 6] = [
CubeFace::PosX, CubeFace::NegX,
CubeFace::PosY, CubeFace::NegY,
CubeFace::PosZ, CubeFace::NegZ,
];
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum Kind {
D1(Size),
D1Array(Size, Layer),
D2(Size, Size, AaMode),
D2Array(Size, Size, Layer, AaMode),
D3(Size, Size, Size),
Cube(Size),
CubeArray(Size, Layer),
}
impl Kind {
pub fn get_dimensions(&self) -> Dimensions {
let s0 = AaMode::Single;
match *self {
Kind::D1(w) => (w, 1, 1, s0),
Kind::D1Array(w, a) => (w, 1, a as Size, s0),
Kind::D2(w, h, s) => (w, h, 1, s),
Kind::D2Array(w, h, a, s) => (w, h, a as Size, s),
Kind::D3(w, h, d) => (w, h, d, s0),
Kind::Cube(w) => (w, w, 6, s0),
Kind::CubeArray(w, a) => (w, w, 6 * (a as Size), s0)
}
}
pub fn get_level_dimensions(&self, level: Level) -> Dimensions {
use std::cmp::{max, min};
let map = |val| max(min(val, 1), val >> min(level, MAX_LEVEL));
let (w, h, da, _) = self.get_dimensions();
(map(w), map(h), map(da), AaMode::Single)
}
pub fn get_num_levels(&self) -> Level {
use std::cmp::max;
let (w, h, d, aa) = self.get_dimensions();
let dominant = max(max(w, h), d);
if aa == AaMode::Single {
(1..).find(|level| dominant>>level <= 1).unwrap()
}else {
1
}
}
pub fn get_num_slices(&self) -> Option<Layer> {
match *self {
Kind::D1(..) | Kind::D2(..) | Kind::D3(..) | Kind::Cube(..) => None,
Kind::D1Array(_, a) => Some(a),
Kind::D2Array(_, _, a, _) => Some(a),
Kind::CubeArray(_, a) => Some(a),
}
}
pub fn is_cube(&self) -> bool {
match *self {
Kind::Cube(_) | Kind::CubeArray(_, _) => true,
_ => false,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum Mipmap {
Provided,
Allocated,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ImageInfoCommon<F> {
pub xoffset: Size,
pub yoffset: Size,
pub zoffset: Size,
pub width: Size,
pub height: Size,
pub depth: Size,
pub format: F,
pub mipmap: Level,
}
pub type RawImageInfo = ImageInfoCommon<format::Format>;
pub type NewImageInfo = ImageInfoCommon<()>;
impl<F> ImageInfoCommon<F> {
pub fn get_texel_count(&self) -> usize {
use std::cmp::max;
max(1, self.width) as usize *
max(1, self.height) as usize *
max(1, self.depth) as usize
}
pub fn convert<T>(&self, new_format: T) -> ImageInfoCommon<T> {
ImageInfoCommon {
xoffset: self.xoffset,
yoffset: self.yoffset,
zoffset: self.zoffset,
width: self.width,
height: self.height,
depth: self.depth,
format: new_format,
mipmap: self.mipmap,
}
}
pub fn is_inside(&self, (w, h, d, aa): Dimensions) -> bool {
aa == AaMode::Single &&
self.xoffset + self.width <= w &&
self.yoffset + self.height <= h &&
self.zoffset + self.depth <= d
}
}
impl RawImageInfo {
pub fn get_byte_count(&self) -> usize {
let texel_bytes = self.format.0.get_total_bits() / 8;
self.get_texel_count() * (texel_bytes as usize)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct TextureCopyRegion<T> {
pub texture: T,
pub kind: Kind,
pub cube_face: Option<CubeFace>,
pub info: RawImageInfo,
}
impl<T> TextureCopyRegion<T> {
pub fn with_texture<U>(self, texture: U) -> TextureCopyRegion<U> {
TextureCopyRegion {
texture,
kind: self.kind,
cube_face: self.cube_face,
info: self.info,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum WrapMode {
Tile,
Mirror,
Clamp,
Border,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Lod(i16);
impl From<f32> for Lod {
fn from(v: f32) -> Lod {
Lod((v * 8.0) as i16)
}
}
impl Into<f32> for Lod {
fn into(self) -> f32 {
self.0 as f32 / 8.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct PackedColor(pub u32);
impl From<[f32; 4]> for PackedColor {
fn from(c: [f32; 4]) -> PackedColor {
PackedColor(c.iter().rev().fold(0, |u, &c| {
(u<<8) + (c * 255.0) as u32
}))
}
}
impl Into<[f32; 4]> for PackedColor {
fn into(self) -> [f32; 4] {
let mut out = [0.0; 4];
for i in 0 .. 4 {
let byte = (self.0 >> (i<<3)) & 0xFF;
out[i] = byte as f32 / 255.0;
}
out
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct SamplerInfo {
pub filter: FilterMethod,
pub wrap_mode: (WrapMode, WrapMode, WrapMode),
#[cfg_attr(feature = "serialize", serde(default = "SamplerInfo::def_lod_bias"))]
pub lod_bias: Lod,
#[cfg_attr(feature = "serialize", serde(default = "SamplerInfo::def_lod_range"))]
pub lod_range: (Lod, Lod),
#[cfg_attr(feature = "serialize", serde(default))]
pub comparison: Option<state::Comparison>,
#[cfg_attr(feature = "serialize", serde(default = "SamplerInfo::def_border"))]
pub border: PackedColor,
}
impl SamplerInfo {
pub fn new(filter: FilterMethod, wrap: WrapMode) -> SamplerInfo {
SamplerInfo {
filter: filter,
wrap_mode: (wrap, wrap, wrap),
lod_bias: Self::def_lod_bias(),
lod_range: Self::def_lod_range(),
comparison: None,
border: Self::def_border(),
}
}
fn def_lod_bias() -> Lod {
Lod(0)
}
fn def_lod_range() -> (Lod, Lod) {
(Lod(-8000), Lod(8000))
}
fn def_border() -> PackedColor {
PackedColor(0)
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Info {
pub kind: Kind,
pub levels: Level,
pub format: format::SurfaceType,
pub bind: Bind,
pub usage: Usage,
}
impl Info {
pub fn to_image_info(&self, mip: Level) -> NewImageInfo {
let (w, h, d, _) = self.kind.get_level_dimensions(mip);
ImageInfoCommon {
xoffset: 0,
yoffset: 0,
zoffset: 0,
width: w,
height: h,
depth: d,
format: (),
mipmap: mip,
}
}
pub fn to_raw_image_info(&self, cty: format::ChannelType, mip: Level) -> RawImageInfo {
let format = format::Format(self.format, cty.into());
self.to_image_info(mip).convert(format)
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ResourceDesc {
pub channel: format::ChannelType,
pub layer: Option<Layer>,
pub min: Level,
pub max: Level,
pub swizzle: format::Swizzle,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct RenderDesc {
pub channel: format::ChannelType,
pub level: Level,
pub layer: Option<Layer>,
}
bitflags!(
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct DepthStencilFlags: u8 {
const RO_DEPTH = 0x1;
const RO_STENCIL = 0x2;
const RO_DEPTH_STENCIL = 0x3;
}
);
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct DepthStencilDesc {
pub level: Level,
pub layer: Option<Layer>,
pub flags: DepthStencilFlags,
}
impl From<RenderDesc> for DepthStencilDesc {
fn from(rd: RenderDesc) -> DepthStencilDesc {
DepthStencilDesc {
level: rd.level,
layer: rd.layer,
flags: DepthStencilFlags::empty(),
}
}
}