use crate::texture::any::TextureAny;
use crate::TextureExt;
use crate::GlObject;
use crate::ContextExt;
use crate::gl;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use crate::program::BlockLayout;
use crate::uniforms::AsUniformValue;
use crate::uniforms::LayoutMismatchError;
use crate::uniforms::UniformBlock;
use crate::uniforms::UniformValue;
use crate::uniforms::UniformType;
use crate::uniforms::SamplerBehavior;
pub struct ResidentTexture {
texture: Option<TextureAny>,
handle: gl::types::GLuint64,
}
impl ResidentTexture {
pub fn new(texture: TextureAny) -> Result<ResidentTexture, BindlessTexturesNotSupportedError> {
let handle = {
let mut ctxt = texture.get_context().make_current();
if !ctxt.extensions.gl_arb_bindless_texture {
return Err(BindlessTexturesNotSupportedError);
}
let handle = unsafe { ctxt.gl.GetTextureHandleARB(texture.get_id()) };
unsafe { ctxt.gl.MakeTextureHandleResidentARB(handle) };
ctxt.resident_texture_handles.push(handle);
handle
};
Ok(ResidentTexture {
texture: Some(texture),
handle,
})
}
#[inline]
pub fn into_inner(mut self) -> TextureAny {
self.into_inner_impl()
}
fn into_inner_impl(&mut self) -> TextureAny {
let texture = self.texture.take().unwrap();
{
let mut ctxt = texture.get_context().make_current();
unsafe { ctxt.gl.MakeTextureHandleNonResidentARB(self.handle) };
ctxt.resident_texture_handles.retain(|&t| t != self.handle);
}
texture
}
}
impl Deref for ResidentTexture {
type Target = TextureAny;
#[inline]
fn deref(&self) -> &TextureAny {
self.texture.as_ref().unwrap()
}
}
impl DerefMut for ResidentTexture {
#[inline]
fn deref_mut(&mut self) -> &mut TextureAny {
self.texture.as_mut().unwrap()
}
}
impl Drop for ResidentTexture {
#[inline]
fn drop(&mut self) {
self.into_inner_impl();
}
}
#[derive(Copy, Clone)]
pub struct TextureHandle<'a> {
value: gl::types::GLuint64,
marker: PhantomData<&'a ResidentTexture>,
}
impl<'a> TextureHandle<'a> {
#[inline]
pub fn new(texture: &'a ResidentTexture, _: &SamplerBehavior) -> TextureHandle<'a> {
TextureHandle {
value: texture.handle,
marker: PhantomData,
}
}
#[inline]
pub fn set(&mut self, texture: &'a ResidentTexture, _: &SamplerBehavior) {
self.value = texture.handle;
}
}
impl<'a> AsUniformValue for TextureHandle<'a> {
#[inline]
fn as_uniform_value(&self) -> UniformValue<'_> {
unimplemented!();
}
}
impl<'a> UniformBlock for TextureHandle<'a> {
fn matches(layout: &BlockLayout, base_offset: usize)
-> Result<(), LayoutMismatchError>
{
if let BlockLayout::BasicType { ty, offset_in_buffer } = *layout {
match ty {
UniformType::Sampler1d => (),
UniformType::ISampler1d => (),
UniformType::USampler1d => (),
UniformType::Sampler2d => (),
UniformType::ISampler2d => (),
UniformType::USampler2d => (),
UniformType::Sampler3d => (),
UniformType::ISampler3d => (),
UniformType::USampler3d => (),
UniformType::Sampler1dArray => (),
UniformType::ISampler1dArray => (),
UniformType::USampler1dArray => (),
UniformType::Sampler2dArray => (),
UniformType::ISampler2dArray => (),
UniformType::USampler2dArray => (),
UniformType::SamplerCube => (),
UniformType::ISamplerCube => (),
UniformType::USamplerCube => (),
UniformType::Sampler2dRect => (),
UniformType::ISampler2dRect => (),
UniformType::USampler2dRect => (),
UniformType::Sampler2dRectShadow => (),
UniformType::SamplerCubeArray => (),
UniformType::ISamplerCubeArray => (),
UniformType::USamplerCubeArray => (),
UniformType::SamplerBuffer => (),
UniformType::ISamplerBuffer => (),
UniformType::USamplerBuffer => (),
UniformType::Sampler2dMultisample => (),
UniformType::ISampler2dMultisample => (),
UniformType::USampler2dMultisample => (),
UniformType::Sampler2dMultisampleArray => (),
UniformType::ISampler2dMultisampleArray => (),
UniformType::USampler2dMultisampleArray => (),
UniformType::Sampler1dShadow => (),
UniformType::Sampler2dShadow => (),
UniformType::SamplerCubeShadow => (),
UniformType::Sampler1dArrayShadow => (),
UniformType::Sampler2dArrayShadow => (),
UniformType::SamplerCubeArrayShadow => (),
_ => return Err(LayoutMismatchError::TypeMismatch {
expected: ty,
obtained: UniformType::Sampler2d, })
}
if offset_in_buffer != base_offset {
return Err(LayoutMismatchError::OffsetMismatch {
expected: offset_in_buffer,
obtained: base_offset,
});
}
Ok(())
} else if let BlockLayout::Struct { members } = layout {
if members.len() == 1 {
<TextureHandle<'_> as UniformBlock>::matches(&members[0].1, base_offset)
} else {
Err(LayoutMismatchError::LayoutMismatch {
expected: layout.clone(),
obtained: BlockLayout::BasicType {
ty: UniformType::Sampler2d, offset_in_buffer: base_offset,
}
})
}
} else {
Err(LayoutMismatchError::LayoutMismatch {
expected: layout.clone(),
obtained: BlockLayout::BasicType {
ty: UniformType::Sampler2d, offset_in_buffer: base_offset,
}
})
}
}
#[inline]
fn build_layout(base_offset: usize) -> BlockLayout {
BlockLayout::BasicType {
ty: UniformType::Sampler2d, offset_in_buffer: base_offset,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct BindlessTexturesNotSupportedError;
#[cfg(test)]
mod test {
use std::mem;
use super::TextureHandle;
#[test]
fn texture_handle_size() {
assert_eq!(mem::size_of::<TextureHandle<'_>>(), 8);
}
}