diff --git a/Cargo.toml b/Cargo.toml index 305c3f89dad..1484c2daa54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ backtrace = "0.3.2" lazy_static = "1.0" smallvec = "0.6" fnv = "1.0.5" +bitflags = "1.0" [build-dependencies] gl_generator = "0.9" diff --git a/build/textures.rs b/build/textures.rs index 70f1f920728..e6f19e8665c 100644 --- a/build/textures.rs +++ b/build/textures.rs @@ -325,7 +325,7 @@ fn build_texture(dest: &mut W, ty: TextureType, dimensions: TextureDim use image_format::{{CompressedSrgbFormat, SrgbFormat, UncompressedUintFormat}}; use backend::Facade; - use uniforms::{{UniformValue, AsUniformValue, Sampler}}; + use uniforms::{{UniformValue, AsUniformValue, Sampler, ImageUnit}}; use framebuffer; use Rect; @@ -413,7 +413,7 @@ fn build_texture(dest: &mut W, ty: TextureType, dimensions: TextureDim }} ", name)).unwrap(); - // `UniformValue` trait impl + // `UniformValue` trait impl for samplers { match ty { TextureType::Regular | TextureType::Compressed | @@ -461,6 +461,29 @@ fn build_texture(dest: &mut W, ty: TextureType, dimensions: TextureDim } } + // Generate implementations of image_unit + if (ty == TextureType::Regular || ty == TextureType::Integral || ty == TextureType::Unsigned) && + (dimensions != TextureDimensions::Texture2dMultisample && dimensions != TextureDimensions::Texture2dMultisampleArray ){ + let image_variant = name.replace("Texture", "Image").replace("Cubemap", "ImageCube"); + writeln!(dest, " + impl<'a> AsUniformValue for ImageUnit<'a, {myname}> {{ + #[inline] + fn as_uniform_value(&self) -> UniformValue {{ + UniformValue::{valname}(self.0, Some(self.1)) + }} + }} + + impl {myname} {{ + /// Builds an image unit marker object that allows you to indicate how the + /// texture should be bound to an image unit. + #[inline] + pub fn image_unit(&self) -> ImageUnit<{myname}> {{ + ImageUnit(self, Default::default()) + }} + }} + ", myname = name, valname = image_variant).unwrap(); + } + // `ToXXXAttachment` trait impl if dimensions == TextureDimensions::Texture2d || dimensions == TextureDimensions::Texture2dMultisample || dimensions == TextureDimensions::Texture1d diff --git a/src/backend/mod.rs b/src/backend/mod.rs index a1b3dc083ea..64bc81b3210 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -25,6 +25,7 @@ use version::Version; pub use context::Context; pub use context::ReleaseBehavior; +pub use context::MemoryBarrier; #[cfg(feature = "glutin")] pub mod glutin; diff --git a/src/context/mod.rs b/src/context/mod.rs index acbd1013f2e..644751298f6 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -530,6 +530,14 @@ impl Context { T::from_raw(Cow::Owned(data), dimensions.0, dimensions.1) } + /// Creates a memory barrier, according to the ARB_shader_image_load_store extension + pub fn memory_barrier(&self, barrier: MemoryBarrier) { + let ctxt = self.make_current(); + unsafe { + ctxt.gl.MemoryBarrier(barrier.bits()); + } + } + /// Execute an arbitrary closure with the OpenGL context active. Useful if another /// component needs to directly manipulate OpenGL state. /// @@ -996,3 +1004,21 @@ fn init_debug_callback(context: &Rc, synchronous: bool) { } } } + +bitflags! { + #[doc("Represents which kind of memory barrier to insert")] + pub struct MemoryBarrier: u32 { + const VERTEX_ATTRIB_ARRAY_BARRIER = gl::VERTEX_ATTRIB_ARRAY_BARRIER_BIT; + const ELEMENT_ARRAY_BARRIER = gl::ELEMENT_ARRAY_BARRIER_BIT; + const UNIFORM_BARRIER = gl::UNIFORM_BARRIER_BIT; + const TEXTURE_FETCH_BARRIER = gl::TEXTURE_FETCH_BARRIER_BIT; + const SHADER_IMAGE_ACCESS_BARRIER = gl::SHADER_IMAGE_ACCESS_BARRIER_BIT; + const COMMAND_BARRIER = gl::COMMAND_BARRIER_BIT; + const PIXEL_BUFFER_BARRIER = gl::PIXEL_BUFFER_BARRIER_BIT; + const TEXTURE_UPDATE_BARRIER = gl::TEXTURE_UPDATE_BARRIER_BIT; + const BUFFER_UPDATE_BARRIER = gl::BUFFER_UPDATE_BARRIER_BIT; + const FRAMEBUFFER_BARRIER = gl::FRAMEBUFFER_BARRIER_BIT; + const TRANSFORM_FEEDBACK_BARRIER = gl::TRANSFORM_FEEDBACK_BARRIER_BIT; + const ATOMIC_COUNTER_BARRIER = gl::ATOMIC_COUNTER_BARRIER_BIT; + } +} diff --git a/src/lib.rs b/src/lib.rs index a9bddc9385a..16da095f4c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,6 +97,9 @@ result to the user. #![allow(dead_code)] #![allow(unused_variables)] +#[macro_use] +extern crate bitflags; + #[macro_use] extern crate lazy_static; @@ -946,6 +949,9 @@ pub enum DrawError { /// Tried to enable a clip plane that does not exist. ClipPlaneIndexOutOfBounds, + + /// Tried to use too many image units simultaneously + InsufficientImageUnits, } impl Error for DrawError { @@ -1005,7 +1011,9 @@ impl Error for DrawError { FixedIndexRestartingNotSupported => "Restarting indices (multiple objects per draw call) is not supported by the backend", ClipPlaneIndexOutOfBounds => - "Tried to enable a clip plane that does not exist." + "Tried to enable a clip plane that does not exist.", + InsufficientImageUnits => + "Tried to use more image uniforms that the implementation has support for", } } diff --git a/src/uniforms/bind.rs b/src/uniforms/bind.rs index bd80a4be3f3..0f576610bd4 100644 --- a/src/uniforms/bind.rs +++ b/src/uniforms/bind.rs @@ -21,6 +21,7 @@ use TextureExt; use uniforms::Uniforms; use uniforms::UniformValue; use uniforms::SamplerBehavior; +use uniforms::ImageUnitBehavior; use context::CommandContext; use buffer::Inserter; @@ -41,6 +42,8 @@ impl UniformsExt for U where U: Uniforms { let mut texture_bind_points = Bitsfield::new(); let mut uniform_buffer_bind_points = Bitsfield::new(); let mut shared_storage_buffer_bind_points = Bitsfield::new(); + let mut image_unit_bind_points = Bitsfield::new(); + image_unit_bind_points.set_used(0); // Trying to attach data to image unit 0 would not go well // Subroutine uniforms must be bound all at once, so we collect them first and process them at the end. // The vec contains the uniform we want to set and the value we want to set it to. @@ -64,7 +67,7 @@ impl UniformsExt for U where U: Uniforms { } match bind_uniform(&mut ctxt, &value, program, uniform.location, - &mut texture_bind_points, name) + &mut texture_bind_points, &mut image_unit_bind_points, name) { Ok(_) => (), Err(e) => { @@ -241,7 +244,9 @@ fn bind_shared_storage_block<'a, P>(ctxt: &mut context::CommandContext, value: & fn bind_uniform

(ctxt: &mut context::CommandContext, value: &UniformValue, program: &P, location: gl::types::GLint, - texture_bind_points: &mut Bitsfield, name: &str) + texture_bind_points: &mut Bitsfield, + image_unit_bind_points: &mut Bitsfield, + name: &str) -> Result<(), DrawError> where P: ProgramExt { assert!(location >= 0); @@ -577,6 +582,69 @@ fn bind_uniform

(ctxt: &mut context::CommandContext, UniformValue::BufferTexture(texture) => { bind_texture_uniform(ctxt, &texture, None, location, program, texture_bind_points) }, + UniformValue::Image1d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImage1d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImage1d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::Image2d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImage2d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImage2d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::Image3d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImage3d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImage3d(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::Image1dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImage1dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImage1dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::Image2dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImage2dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImage2dArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::ImageCube(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImageCube(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImageCube(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::ImageCubeArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::IntegralImageCubeArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, + UniformValue::UnsignedImageCubeArray(texture, unit) => { + bind_image_uniform(ctxt, &**texture, unit, location, program, image_unit_bind_points) + }, } } @@ -654,3 +722,43 @@ fn bind_texture_uniform(ctxt: &mut context::CommandContext, Ok(()) } + +fn bind_image_uniform( + ctxt: &mut context::CommandContext, + texture: &T, unit_behavior: Option, + location: gl::types::GLint, program: &P, + image_unit_bind_points: &mut Bitsfield +) -> Result<(), DrawError> + where P: ProgramExt, T: TextureExt +{ + use ToGlEnum; + + let unit_behavior = unit_behavior.expect("Unit behavior should always be provided"); + let image_unit = match image_unit_bind_points.get_unused() { + Some(unit) => unit, + None => return Err(DrawError::InsufficientImageUnits), + }; + + // Update the program to use the right unit + program.set_uniform(ctxt, location, + &RawUniformValue::SignedInt(image_unit as gl::types::GLint)); + + let (layered, layer) = match unit_behavior.layer { + None => (false, 0), + Some(l) => (true, l) + }; + + unsafe { + ctxt.gl.BindImageTexture( + image_unit as gl::types::GLuint, + texture.get_texture_id(), + unit_behavior.level as i32, + if layered { 1 } else { 0 }, + layer as i32, + unit_behavior.access.to_glenum(), + unit_behavior.format.to_glenum(), + ) + } + + Ok(()) +} diff --git a/src/uniforms/image_unit.rs b/src/uniforms/image_unit.rs new file mode 100644 index 00000000000..b0c579ef245 --- /dev/null +++ b/src/uniforms/image_unit.rs @@ -0,0 +1,222 @@ +//! Image units, views into specific planes of textures +use ToGlEnum; +use gl; + +/// How we bind a texture to an image unit +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct ImageUnitBehavior { + /// The mip level to bind + pub level: usize, + pub(crate) layer: Option, + /// How the shader will access the image unit + pub access: ImageUnitAccess, + /// How the shader should interpret the image + pub format: ImageUnitFormat, +} + +impl Default for ImageUnitBehavior { + #[inline] + fn default() -> ImageUnitBehavior { + ImageUnitBehavior { + level: 0, + layer: None, + access: ImageUnitAccess::Read, + format: ImageUnitFormat::R32I, + } + } +} + +/// An image unit uniform marker +pub struct ImageUnit<'t, T: 't>(pub &'t T, pub ImageUnitBehavior); + +impl<'t, T: 't> ImageUnit<'t, T> { + /// Create a new marker + pub fn new(texture: &'t T) -> ImageUnit<'t, T> { + ImageUnit(texture, Default::default()) + } + + /// Set the mip level that will be bound + pub fn set_level(mut self, level: usize) -> Self { + self.1.level = level; + self + } + + /// Sets the layer of the texture to bind, or None to disable layer binding + /// TODO: only implement this for texture types where layering makes sense + pub fn set_layer(mut self, layer: Option) -> Self { + self.1.layer = layer; + self + } + + /// State how the shader will access the image unit + pub fn set_access(mut self, access: ImageUnitAccess) -> Self { + self.1.access = access; + self + } + + /// State how the shader should interpret the image data + pub fn set_format(mut self, format: ImageUnitFormat) -> Self { + self.1.format = format; + self + } +} + +/// States how the shader will access the image unit +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum ImageUnitAccess { + /// The shader will only read from the image unit + Read, + /// The shader will only write to the image unit + Write, + /// The shader will perform both reads and writes to the image unit + ReadWrite, +} + +impl ToGlEnum for ImageUnitAccess { + #[inline] + fn to_glenum(&self) -> gl::types::GLenum { + match *self { + ImageUnitAccess::Read => gl::READ_ONLY, + ImageUnitAccess::Write => gl::WRITE_ONLY, + ImageUnitAccess::ReadWrite => gl::READ_WRITE, + } + } +} + +/// How the shader should interpret the data in the image +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum ImageUnitFormat { + /// The image elements are 4-component 32 bit floating point + RGBA32F, + /// The image elements are 4-component 16 bit floating point + RGBA16F, + /// The image elements are 2-component 32 bit floating point + RG32F, + /// The image elements are 4-component 16 bit floating point + RG16F, + /// The image elements are 2 11-bit floats and 1 10-bit float + R11FG11FB10F, + /// The image elements are 1-component 32 bit floating point + R32F, + /// The image elements are 4-component 16 bit floating point + R16F, + + /// The image elements are 4-component 32 bit unsigned integer + RGBA32UI, + /// The image elements are 4-component 16 bit unsigned integer + RGBA16UI, + /// The image elements have 3 10-bit unsigned integer components and 1 2-bit alpha component + RGB10A2UI, + /// The image elements are 4-component 8 bit unsigned integer + RGBA8UI, + /// The image elements are 2-component 32 bit unsigned integer + RG32UI, + /// The image elements are 2-component 16 bit unsigned integer + RG16UI, + /// The image elements are 2-component 8 bit unsigned integer + RG8UI, + /// The image elements are 1-component 32 bit unsigned integer + R32UI, + /// The image elements are 1-component 16 bit unsigned integer + R16UI, + /// The image elements are 1-component 8 bit unsigned integer + R8UI, + + /// The image elements are 4-component 32 bit signed integer + RGBA32I, + /// The image elements are 4-component 16 bit signed integer + RGBA16I, + /// The image elements are 4-component 8 bit signed integer + RGBA8I, + /// The image elements are 2-component 32 bit signed integer + RG32I, + /// The image elements are 2-component 16 bit signed integer + RG16I, + /// The image elements are 2-component 8 bit signed integer + RG8I, + /// The image elements are 1-component 32 bit signed integer + R32I, + /// The image elements are 1-component 16 bit signed integer + R16I, + /// The image elements are 1-component 8 bit signed integer + R8I, + + /// The image elements are 4-component 16 bit floating point + RGBA16, + /// The image elements are 3-component 10 bit floating point with 2 alpha bits + RGB10A2, + /// The image elements are 4-component 8 bit floating point + RGBA8, + /// The image elements are 2-component 16 bit floating point + RG16, + /// The image elements are 2-component 8 bit floating point + RG8, + /// The image elements are 1-component 16 bit floating point + R16, + /// The image elements are 1-component 8 bit floating point + R8, + + /// The image elements are 4-component 16 bit floating point, normalized to the -1.0 to 1.0 range + RGBA16snorm, + /// The image elements are 4-component 8 bit floating point, normalized to the -1.0 to 1.0 range + RGBA8snorm, + /// The image elements are 2-component 16 bit floating point, normalized to the -1.0 to 1.0 range + RG16snorm, + /// The image elements are 2-component 8 bit floating point, normalized to the -1.0 to 1.0 range + RG8snorm, + /// The image elements are 1-component 16 bit floating point, normalized to the -1.0 to 1.0 range + R16snorm, + /// The image elements are 1-component 8 bit floating point, normalized to the -1.0 to 1.0 range + R8snorm, +} + +impl ToGlEnum for ImageUnitFormat { + #[inline] + fn to_glenum(&self) -> gl::types::GLenum { + match *self { + ImageUnitFormat::RGBA32F => gl::RGBA32F, + ImageUnitFormat::RGBA16F => gl::RGBA16F, + ImageUnitFormat::RG32F => gl::RG32F, + ImageUnitFormat::RG16F => gl::RG16F, + ImageUnitFormat::R11FG11FB10F => gl::R11F_G11F_B10F, + ImageUnitFormat::R32F => gl::R32F, + ImageUnitFormat::R16F => gl::R16F, + + ImageUnitFormat::RGBA32UI => gl::RGBA32UI, + ImageUnitFormat::RGBA16UI => gl::RGBA16UI, + ImageUnitFormat::RGB10A2UI => gl::RGB10_A2UI, + ImageUnitFormat::RGBA8UI => gl::RGBA8UI, + ImageUnitFormat::RG32UI => gl::RG32UI, + ImageUnitFormat::RG16UI => gl::RG16UI, + ImageUnitFormat::RG8UI => gl::RG8UI, + ImageUnitFormat::R32UI => gl::R32UI, + ImageUnitFormat::R16UI => gl::R16UI, + ImageUnitFormat::R8UI => gl::R8UI, + + ImageUnitFormat::RGBA32I => gl::RGBA32I, + ImageUnitFormat::RGBA16I => gl::RGBA16I, + ImageUnitFormat::RGBA8I => gl::RGBA8I, + ImageUnitFormat::RG32I => gl::RG32I, + ImageUnitFormat::RG16I => gl::RG16I, + ImageUnitFormat::RG8I => gl::RG8I, + ImageUnitFormat::R32I => gl::R32I, + ImageUnitFormat::R16I => gl::R16I, + ImageUnitFormat::R8I => gl::R8I, + + ImageUnitFormat::RGBA16 => gl::RGBA16, + ImageUnitFormat::RGB10A2 => gl::RGB10_A2, + ImageUnitFormat::RGBA8 => gl::RGBA8, + ImageUnitFormat::RG16 => gl::RG16, + ImageUnitFormat::RG8 => gl::RG8, + ImageUnitFormat::R16 => gl::R16, + ImageUnitFormat::R8 => gl::R8, + + ImageUnitFormat::RGBA16snorm => gl::RGBA16_SNORM, + ImageUnitFormat::RGBA8snorm => gl::RGBA8_SNORM, + ImageUnitFormat::RG16snorm => gl::RG16_SNORM, + ImageUnitFormat::RG8snorm => gl::RG8_SNORM, + ImageUnitFormat::R16snorm => gl::R16_SNORM, + ImageUnitFormat::R8snorm => gl::R8_SNORM, + } + } +} diff --git a/src/uniforms/mod.rs b/src/uniforms/mod.rs index ac6d6d7bfb9..945a8bb40cf 100644 --- a/src/uniforms/mod.rs +++ b/src/uniforms/mod.rs @@ -143,6 +143,8 @@ let program = glium::Program::from_source(&display, pub use self::buffer::UniformBuffer; pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter}; pub use self::sampler::{Sampler, SamplerBehavior}; +pub use self::image_unit::{ImageUnitAccess, ImageUnitFormat}; +pub use self::image_unit::{ImageUnit, ImageUnitBehavior}; pub use self::uniforms::{EmptyUniforms, UniformsStorage}; pub use self::value::{UniformValue, UniformType}; @@ -156,6 +158,7 @@ use program::BlockLayout; mod bind; mod buffer; +mod image_unit; mod sampler; mod uniforms; mod value; diff --git a/src/uniforms/value.rs b/src/uniforms/value.rs index 5f366b78064..e374f010ae3 100644 --- a/src/uniforms/value.rs +++ b/src/uniforms/value.rs @@ -8,6 +8,8 @@ use uniforms::LayoutMismatchError; use uniforms::UniformBlock; use uniforms::SamplerBehavior; +use uniforms::ImageUnitBehavior; + use buffer::BufferAnySlice; /// Type of a uniform in a program. @@ -124,6 +126,9 @@ pub enum UniformType { Image2dArray, IImage2dArray, UImage2dArray, + ImageCubeArray, + IImageCubeArray, + UImageCubeArray, Image2dMultisample, IImage2dMultisample, UImage2dMultisample, @@ -240,6 +245,28 @@ pub enum UniformValue<'a> { UnsignedCubemapArray(&'a texture::UnsignedCubemapArray, Option), DepthCubemapArray(&'a texture::DepthCubemapArray, Option), BufferTexture(texture::buffer_texture::BufferTextureRef<'a>), + + Image1d(&'a texture::Texture1d, Option), + IntegralImage1d(&'a texture::IntegralTexture1d, Option), + UnsignedImage1d(&'a texture::UnsignedTexture1d, Option), + Image2d(&'a texture::Texture2d, Option), + IntegralImage2d(&'a texture::IntegralTexture2d, Option), + UnsignedImage2d(&'a texture::UnsignedTexture2d, Option), + Image3d(&'a texture::Texture3d, Option), + IntegralImage3d(&'a texture::IntegralTexture3d, Option), + UnsignedImage3d(&'a texture::UnsignedTexture3d, Option), + Image1dArray(&'a texture::Texture1dArray, Option), + IntegralImage1dArray(&'a texture::IntegralTexture1dArray, Option), + UnsignedImage1dArray(&'a texture::UnsignedTexture1dArray, Option), + Image2dArray(&'a texture::Texture2dArray, Option), + IntegralImage2dArray(&'a texture::IntegralTexture2dArray, Option), + UnsignedImage2dArray(&'a texture::UnsignedTexture2dArray, Option), + ImageCube(&'a texture::Cubemap, Option), + IntegralImageCube(&'a texture::IntegralCubemap, Option), + UnsignedImageCube(&'a texture::UnsignedCubemap, Option), + ImageCubeArray(&'a texture::CubemapArray, Option), + IntegralImageCubeArray(&'a texture::IntegralCubemapArray, Option), + UnsignedImageCubeArray(&'a texture::UnsignedCubemapArray, Option), } impl<'a> Clone for UniformValue<'a> { @@ -348,6 +375,27 @@ impl<'a> UniformValue<'a> { (&UniformValue::IntegralTexture2dMultisample(..), UniformType::ISampler2dMultisample) => true, (&UniformValue::UnsignedTexture2dMultisample(..), UniformType::USampler2dMultisample) => true, (&UniformValue::DepthTexture2dMultisample(..), UniformType::Sampler2dMultisample) => true, + (&UniformValue::Image1d(..), UniformType::Image1d) => true, + (&UniformValue::IntegralImage1d(..), UniformType::IImage1d) => true, + (&UniformValue::UnsignedImage1d(..), UniformType::UImage1d) => true, + (&UniformValue::Image2d(..), UniformType::Image2d) => true, + (&UniformValue::IntegralImage2d(..), UniformType::IImage2d) => true, + (&UniformValue::UnsignedImage2d(..), UniformType::UImage2d) => true, + (&UniformValue::Image3d(..), UniformType::Image3d) => true, + (&UniformValue::IntegralImage3d(..), UniformType::IImage3d) => true, + (&UniformValue::UnsignedImage3d(..), UniformType::UImage3d) => true, + (&UniformValue::Image1dArray(..), UniformType::Image1dArray) => true, + (&UniformValue::IntegralImage1dArray(..), UniformType::IImage1dArray) => true, + (&UniformValue::UnsignedImage1dArray(..), UniformType::UImage1dArray) => true, + (&UniformValue::Image2dArray(..), UniformType::Image2dArray) => true, + (&UniformValue::IntegralImage2dArray(..), UniformType::IImage2dArray) => true, + (&UniformValue::UnsignedImage2dArray(..), UniformType::UImage2dArray) => true, + (&UniformValue::ImageCube(..), UniformType::ImageCube) => true, + (&UniformValue::IntegralImageCube(..), UniformType::IImageCube) => true, + (&UniformValue::UnsignedImageCube(..), UniformType::UImageCube) => true, + (&UniformValue::ImageCubeArray(..), UniformType::ImageCubeArray) => true, + (&UniformValue::IntegralImageCubeArray(..), UniformType::IImageCubeArray) => true, + (&UniformValue::UnsignedImageCubeArray(..), UniformType::UImageCubeArray) => true, _ => false, } }