use super::*;
use crate::{gl46 as native_gl, version::Version};
use std::ffi::CStr;
use std::ptr;
use std::{collections::HashSet, ffi::CString, num::NonZeroU32};
#[derive(Default)]
struct Constants {
max_label_length: i32,
}
struct DebugCallbackRawPtr {
callback: *mut std::os::raw::c_void,
}
impl Drop for DebugCallbackRawPtr {
fn drop(&mut self) {
unsafe {
let thin_ptr = Box::from_raw(self.callback as *mut DebugCallback);
let callback = *thin_ptr;
drop(callback);
}
}
}
pub struct Context {
raw: native_gl::GlFns,
extensions: HashSet<String>,
constants: Constants,
version: Version,
debug_callback: Option<DebugCallbackRawPtr>,
}
impl Context {
pub unsafe fn from_loader_function_cstr<F>(mut loader_function: F) -> Self
where
F: FnMut(&CStr) -> *const std::os::raw::c_void,
{
let raw: native_gl::GlFns =
native_gl::GlFns::load_with(|p: *const std::os::raw::c_char| {
let c_str = std::ffi::CStr::from_ptr(p);
loader_function(c_str) as *mut std::os::raw::c_void
});
let raw_string = raw.GetString(VERSION);
if raw_string.is_null() {
panic!("Reading GL_VERSION failed. Make sure there is a valid GL context currently active.")
}
let raw_version = std::ffi::CStr::from_ptr(raw_string as *const native_gl::GLchar)
.to_str()
.unwrap()
.to_owned();
let version = Version::parse(&raw_version).unwrap();
let mut context = Self {
raw,
extensions: HashSet::new(),
constants: Constants::default(),
version,
debug_callback: None,
};
if (context.version >= Version::new(3, 0, None, String::from("")))
|| (context.version >= Version::new_embedded(3, 0, String::from("")))
{
let num_extensions = context.get_parameter_i32(NUM_EXTENSIONS);
for i in 0..num_extensions {
let extension_name = context.get_parameter_indexed_string(EXTENSIONS, i as u32);
context.extensions.insert(extension_name);
}
} else {
context.extensions.extend(
context
.get_parameter_string(EXTENSIONS)
.split(' ')
.map(|s| s.to_string()),
);
};
context.constants.max_label_length = if context.supports_debug() {
context.get_parameter_i32(MAX_LABEL_LENGTH)
} else {
0
};
context
}
pub unsafe fn from_loader_function<F>(mut loader_function: F) -> Self
where
F: FnMut(&str) -> *const std::os::raw::c_void,
{
Self::from_loader_function_cstr(move |name| loader_function(name.to_str().unwrap()))
}
#[deprecated = "Use the NativeTexture constructor instead"]
pub unsafe fn create_texture_from_gl_name(gl_name: native_gl::GLuint) -> NativeTexture {
NativeTexture(non_zero_gl_name(gl_name))
}
#[deprecated = "Use the NativeFramebuffer constructor instead"]
pub unsafe fn create_framebuffer_from_gl_name(gl_name: native_gl::GLuint) -> NativeFramebuffer {
NativeFramebuffer(non_zero_gl_name(gl_name))
}
}
impl std::fmt::Debug for Context {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Native_GL_Context")
}
}
fn non_zero_gl_name(value: native_gl::GLuint) -> NonZeroU32 {
NonZeroU32::new(value as u32).expect("expected non-zero GL name")
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeShader(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeProgram(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeBuffer(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeVertexArray(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeTexture(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeSampler(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeFence(pub native_gl::GLsync);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeFramebuffer(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeRenderbuffer(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeQuery(pub NonZeroU32);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeUniformLocation(pub native_gl::GLuint);
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct NativeTransformFeedback(pub NonZeroU32);
impl HasContext for Context {
type Shader = NativeShader;
type Program = NativeProgram;
type Buffer = NativeBuffer;
type VertexArray = NativeVertexArray;
type Texture = NativeTexture;
type Sampler = NativeSampler;
type Fence = NativeFence;
type Framebuffer = NativeFramebuffer;
type Renderbuffer = NativeRenderbuffer;
type Query = NativeQuery;
type UniformLocation = NativeUniformLocation;
type TransformFeedback = NativeTransformFeedback;
fn supported_extensions(&self) -> &HashSet<String> {
&self.extensions
}
fn supports_debug(&self) -> bool {
if self.extensions.contains("GL_KHR_debug") {
true
} else if self.version.is_embedded {
self.version.major == 3 && self.version.minor >= 2
} else {
self.version.major == 4 && self.version.minor >= 3
}
}
fn version(&self) -> &Version {
&self.version
}
unsafe fn create_framebuffer(&self) -> Result<Self::Framebuffer, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenFramebuffers(1, &mut name);
Ok(NativeFramebuffer(non_zero_gl_name(name)))
}
unsafe fn is_framebuffer(&self, framebuffer: Self::Framebuffer) -> bool {
let gl = &self.raw;
gl.IsFramebuffer(framebuffer.0.get()) != 0
}
unsafe fn create_query(&self) -> Result<Self::Query, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenQueries(1, &mut name);
Ok(NativeQuery(non_zero_gl_name(name)))
}
unsafe fn create_renderbuffer(&self) -> Result<Self::Renderbuffer, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenRenderbuffers(1, &mut name);
Ok(NativeRenderbuffer(non_zero_gl_name(name)))
}
unsafe fn is_renderbuffer(&self, renderbuffer: Self::Renderbuffer) -> bool {
let gl = &self.raw;
gl.IsRenderbuffer(renderbuffer.0.get()) != 0
}
unsafe fn create_sampler(&self) -> Result<Self::Sampler, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenSamplers(1, &mut name);
Ok(NativeSampler(non_zero_gl_name(name)))
}
unsafe fn create_shader(&self, shader_type: u32) -> Result<Self::Shader, String> {
let gl = &self.raw;
Ok(NativeShader(non_zero_gl_name(
gl.CreateShader(shader_type as u32),
)))
}
unsafe fn is_shader(&self, shader: Self::Shader) -> bool {
let gl = &self.raw;
gl.IsShader(shader.0.get()) != 0
}
unsafe fn create_texture(&self) -> Result<Self::Texture, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenTextures(1, &mut name);
Ok(NativeTexture(non_zero_gl_name(name)))
}
unsafe fn create_named_texture(&self, target: u32) -> Result<Self::Texture, String> {
let gl = &self.raw;
let mut name = 0;
gl.CreateTextures(target, 1, &mut name);
Ok(NativeTexture(non_zero_gl_name(name)))
}
unsafe fn is_texture(&self, texture: Self::Texture) -> bool {
let gl = &self.raw;
gl.IsTexture(texture.0.get()) != 0
}
unsafe fn delete_shader(&self, shader: Self::Shader) {
let gl = &self.raw;
gl.DeleteShader(shader.0.get());
}
unsafe fn shader_source(&self, shader: Self::Shader, source: &str) {
let gl = &self.raw;
gl.ShaderSource(
shader.0.get(),
1,
&(source.as_ptr() as *const native_gl::GLchar),
&(source.len() as native_gl::GLint),
);
}
unsafe fn compile_shader(&self, shader: Self::Shader) {
let gl = &self.raw;
gl.CompileShader(shader.0.get());
}
unsafe fn get_shader_completion_status(&self, shader: Self::Shader) -> bool {
let gl = &self.raw;
let mut status = 0;
gl.GetShaderiv(shader.0.get(), COMPLETION_STATUS, &mut status);
1 == status
}
unsafe fn get_shader_compile_status(&self, shader: Self::Shader) -> bool {
let gl = &self.raw;
let mut status = 0;
gl.GetShaderiv(shader.0.get(), COMPILE_STATUS, &mut status);
1 == status
}
unsafe fn get_shader_info_log(&self, shader: Self::Shader) -> String {
let gl = &self.raw;
let mut length = 0;
gl.GetShaderiv(shader.0.get(), INFO_LOG_LENGTH, &mut length);
if length > 0 {
let mut log = String::with_capacity(length as usize);
log.extend(std::iter::repeat('\0').take(length as usize));
gl.GetShaderInfoLog(
shader.0.get(),
length,
&mut length,
(&log[..]).as_ptr() as *mut native_gl::GLchar,
);
log.truncate(length as usize);
log
} else {
String::from("")
}
}
unsafe fn get_tex_image(
&self,
target: u32,
level: i32,
format: u32,
ty: u32,
pixels: PixelPackData,
) {
let gl = &self.raw;
gl.GetTexImage(
target,
level,
format,
ty,
match pixels {
PixelPackData::BufferOffset(offset) => offset as *mut std::ffi::c_void,
PixelPackData::Slice(data) => data.as_mut_ptr() as *mut std::ffi::c_void,
},
);
}
unsafe fn create_program(&self) -> Result<Self::Program, String> {
let gl = &self.raw;
Ok(NativeProgram(non_zero_gl_name(gl.CreateProgram())))
}
unsafe fn is_program(&self, program: Self::Program) -> bool {
let gl = &self.raw;
gl.IsProgram(program.0.get()) != 0
}
unsafe fn delete_program(&self, program: Self::Program) {
let gl = &self.raw;
gl.DeleteProgram(program.0.get());
}
unsafe fn attach_shader(&self, program: Self::Program, shader: Self::Shader) {
let gl = &self.raw;
gl.AttachShader(program.0.get(), shader.0.get());
}
unsafe fn detach_shader(&self, program: Self::Program, shader: Self::Shader) {
let gl = &self.raw;
gl.DetachShader(program.0.get(), shader.0.get());
}
unsafe fn link_program(&self, program: Self::Program) {
let gl = &self.raw;
gl.LinkProgram(program.0.get());
}
unsafe fn get_program_completion_status(&self, program: Self::Program) -> bool {
let gl = &self.raw;
let mut status = 0;
gl.GetProgramiv(program.0.get(), COMPLETION_STATUS, &mut status);
1 == status
}
unsafe fn get_program_link_status(&self, program: Self::Program) -> bool {
let gl = &self.raw;
let mut status = 0;
gl.GetProgramiv(program.0.get(), LINK_STATUS, &mut status);
1 == status
}
unsafe fn get_program_info_log(&self, program: Self::Program) -> String {
let gl = &self.raw;
let mut length = 0;
gl.GetProgramiv(program.0.get(), INFO_LOG_LENGTH, &mut length);
if length > 0 {
let mut log = String::with_capacity(length as usize);
log.extend(std::iter::repeat('\0').take(length as usize));
gl.GetProgramInfoLog(
program.0.get(),
length,
&mut length,
(&log[..]).as_ptr() as *mut native_gl::GLchar,
);
log.truncate(length as usize);
log
} else {
String::from("")
}
}
unsafe fn get_program_resource_i32(
&self,
program: Self::Program,
interface: u32,
index: u32,
properties: &[u32],
) -> Vec<i32> {
let gl = &self.raw;
let mut length = 0i32;
gl.GetProgramResourceiv(
program.0.get(),
interface,
index,
properties.len() as i32,
properties.as_ptr(),
0,
&mut length,
ptr::null_mut(),
);
let mut params = vec![0i32; length as usize];
gl.GetProgramResourceiv(
program.0.get(),
interface,
index,
properties.len() as i32,
properties.as_ptr(),
length,
&mut length,
params.as_mut_ptr(),
);
params
}
unsafe fn get_active_uniforms(&self, program: Self::Program) -> u32 {
let gl = &self.raw;
let mut count = 0;
gl.GetProgramiv(program.0.get(), ACTIVE_UNIFORMS, &mut count);
count as u32
}
unsafe fn get_active_uniform(
&self,
program: Self::Program,
index: u32,
) -> Option<ActiveUniform> {
let gl = &self.raw;
let mut uniform_max_size = 0;
gl.GetProgramiv(
program.0.get(),
ACTIVE_UNIFORM_MAX_LENGTH,
&mut uniform_max_size,
);
let mut name = String::with_capacity(uniform_max_size as usize);
name.extend(std::iter::repeat('\0').take(uniform_max_size as usize));
let mut length = 0;
let mut size = 0;
let mut utype = 0;
gl.GetActiveUniform(
program.0.get(),
index,
uniform_max_size,
&mut length,
&mut size,
&mut utype,
name.as_ptr() as *mut native_gl::GLchar,
);
name.truncate(length as usize);
Some(ActiveUniform { size, utype, name })
}
unsafe fn use_program(&self, program: Option<Self::Program>) {
let gl = &self.raw;
gl.UseProgram(program.map(|p| p.0.get()).unwrap_or(0));
}
unsafe fn create_buffer(&self) -> Result<Self::Buffer, String> {
let gl = &self.raw;
let mut buffer = 0;
gl.GenBuffers(1, &mut buffer);
Ok(NativeBuffer(non_zero_gl_name(buffer)))
}
unsafe fn create_named_buffer(&self) -> Result<Self::Buffer, String> {
let gl = &self.raw;
let mut buffer = 0;
gl.CreateBuffers(1, &mut buffer);
Ok(NativeBuffer(non_zero_gl_name(buffer)))
}
unsafe fn is_buffer(&self, buffer: Self::Buffer) -> bool {
let gl = &self.raw;
gl.IsBuffer(buffer.0.get()) != 0
}
unsafe fn bind_buffer(&self, target: u32, buffer: Option<Self::Buffer>) {
let gl = &self.raw;
gl.BindBuffer(target, buffer.map(|b| b.0.get()).unwrap_or(0));
}
unsafe fn bind_buffer_base(&self, target: u32, index: u32, buffer: Option<Self::Buffer>) {
let gl = &self.raw;
gl.BindBufferBase(target, index, buffer.map(|b| b.0.get()).unwrap_or(0));
}
unsafe fn bind_buffer_range(
&self,
target: u32,
index: u32,
buffer: Option<Self::Buffer>,
offset: i32,
size: i32,
) {
let gl = &self.raw;
gl.BindBufferRange(
target,
index,
buffer.map(|b| b.0.get()).unwrap_or(0),
offset as isize,
size as isize,
);
}
unsafe fn bind_vertex_buffer(
&self,
binding_index: u32,
buffer: Option<Buffer>,
offset: i32,
stride: i32,
) {
let gl = &self.raw;
gl.BindVertexBuffer(
binding_index,
buffer.map(|b| b.0.get()).unwrap_or(0),
offset as isize,
stride,
);
}
unsafe fn bind_framebuffer(&self, target: u32, framebuffer: Option<Self::Framebuffer>) {
let gl = &self.raw;
gl.BindFramebuffer(target, framebuffer.map(|fb| fb.0.get()).unwrap_or(0));
}
unsafe fn bind_renderbuffer(&self, target: u32, renderbuffer: Option<Self::Renderbuffer>) {
let gl = &self.raw;
gl.BindRenderbuffer(target, renderbuffer.map(|rb| rb.0.get()).unwrap_or(0));
}
unsafe fn blit_framebuffer(
&self,
src_x0: i32,
src_y0: i32,
src_x1: i32,
src_y1: i32,
dst_x0: i32,
dst_y0: i32,
dst_x1: i32,
dst_y1: i32,
mask: u32,
filter: u32,
) {
let gl = &self.raw;
gl.BlitFramebuffer(
src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
);
}
unsafe fn create_vertex_array(&self) -> Result<Self::VertexArray, String> {
let gl = &self.raw;
let mut vertex_array = 0;
gl.GenVertexArrays(1, &mut vertex_array);
Ok(NativeVertexArray(non_zero_gl_name(vertex_array)))
}
unsafe fn delete_vertex_array(&self, vertex_array: Self::VertexArray) {
let gl = &self.raw;
gl.DeleteVertexArrays(1, &vertex_array.0.get());
}
unsafe fn bind_vertex_array(&self, vertex_array: Option<Self::VertexArray>) {
let gl = &self.raw;
gl.BindVertexArray(vertex_array.map(|va| va.0.get()).unwrap_or(0));
}
unsafe fn clear_color(&self, red: f32, green: f32, blue: f32, alpha: f32) {
let gl = &self.raw;
gl.ClearColor(red, green, blue, alpha);
}
unsafe fn supports_f64_precision() -> bool {
true
}
unsafe fn clear_depth_f64(&self, depth: f64) {
let gl = &self.raw;
gl.ClearDepth(depth);
}
unsafe fn clear_depth_f32(&self, depth: f32) {
let gl = &self.raw;
gl.ClearDepthf(depth);
}
unsafe fn clear_stencil(&self, stencil: i32) {
let gl = &self.raw;
gl.ClearStencil(stencil);
}
unsafe fn clear(&self, mask: u32) {
let gl = &self.raw;
gl.Clear(mask);
}
unsafe fn patch_parameter_i32(&self, parameter: u32, value: i32) {
let gl = &self.raw;
gl.PatchParameteri(parameter, value);
}
unsafe fn pixel_store_i32(&self, parameter: u32, value: i32) {
let gl = &self.raw;
gl.PixelStorei(parameter, value);
}
unsafe fn pixel_store_bool(&self, parameter: u32, value: bool) {
let gl = &self.raw;
gl.PixelStorei(parameter, value as i32);
}
unsafe fn bind_frag_data_location(
&self,
program: Self::Program,
color_number: u32,
name: &str,
) {
let gl = &self.raw;
gl.BindFragDataLocation(
program.0.get(),
color_number,
name.as_ptr() as *const native_gl::GLchar,
);
}
unsafe fn buffer_data_size(&self, target: u32, size: i32, usage: u32) {
let gl = &self.raw;
gl.BufferData(target, size as isize, std::ptr::null(), usage);
}
unsafe fn buffer_data_u8_slice(&self, target: u32, data: &[u8], usage: u32) {
let gl = &self.raw;
gl.BufferData(
target,
data.len() as isize,
data.as_ptr() as *const std::ffi::c_void,
usage,
);
}
unsafe fn named_buffer_data_u8_slice(&self, buffer: Self::Buffer, data: &[u8], usage: u32) {
let gl = &self.raw;
gl.NamedBufferData(
buffer.0.get(),
data.len() as isize,
data.as_ptr() as *const std::ffi::c_void,
usage,
);
}
unsafe fn buffer_sub_data_u8_slice(&self, target: u32, offset: i32, src_data: &[u8]) {
let gl = &self.raw;
gl.BufferSubData(
target,
offset as isize,
src_data.len() as isize,
src_data.as_ptr() as *const std::ffi::c_void,
);
}
unsafe fn get_buffer_sub_data(&self, target: u32, offset: i32, dst_data: &mut [u8]) {
let gl = &self.raw;
gl.GetBufferSubData(
target,
offset as isize,
dst_data.len() as isize,
dst_data.as_mut_ptr() as *mut std::ffi::c_void,
);
}
unsafe fn buffer_storage(&self, target: u32, size: i32, data: Option<&[u8]>, flags: u32) {
let gl = &self.raw;
let size = size as isize;
let data = data.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void;
if gl.BufferStorage_is_loaded() {
gl.BufferStorage(target, size, data, flags);
} else {
gl.BufferStorageEXT(target, size, data, flags);
}
}
unsafe fn check_framebuffer_status(&self, target: u32) -> u32 {
let gl = &self.raw;
gl.CheckFramebufferStatus(target)
}
unsafe fn clear_buffer_i32_slice(&self, target: u32, draw_buffer: u32, values: &[i32]) {
let gl = &self.raw;
gl.ClearBufferiv(target, draw_buffer as i32, values.as_ptr());
}
unsafe fn clear_buffer_u32_slice(&self, target: u32, draw_buffer: u32, values: &[u32]) {
let gl = &self.raw;
gl.ClearBufferuiv(target, draw_buffer as i32, values.as_ptr());
}
unsafe fn clear_buffer_f32_slice(&self, target: u32, draw_buffer: u32, values: &[f32]) {
let gl = &self.raw;
gl.ClearBufferfv(target, draw_buffer as i32, values.as_ptr());
}
unsafe fn clear_buffer_depth_stencil(
&self,
target: u32,
draw_buffer: u32,
depth: f32,
stencil: i32,
) {
let gl = &self.raw;
gl.ClearBufferfi(target, draw_buffer as i32, depth, stencil);
}
unsafe fn client_wait_sync(&self, fence: Self::Fence, flags: u32, timeout: i32) -> u32 {
let gl = &self.raw;
gl.ClientWaitSync(fence.0, flags, timeout as u64)
}
unsafe fn wait_sync(&self, fence: Self::Fence, flags: u32, timeout: u64) {
let gl = &self.raw;
gl.WaitSync(fence.0, flags, timeout)
}
unsafe fn copy_buffer_sub_data(
&self,
src_target: u32,
dst_target: u32,
src_offset: i32,
dst_offset: i32,
size: i32,
) {
let gl = &self.raw;
gl.CopyBufferSubData(
src_target,
dst_target,
src_offset as isize,
dst_offset as isize,
size as isize,
);
}
unsafe fn copy_image_sub_data(
&self,
src_name: Self::Texture,
src_target: u32,
src_level: i32,
src_x: i32,
src_y: i32,
src_z: i32,
dst_name: Self::Texture,
dst_target: u32,
dst_level: i32,
dst_x: i32,
dst_y: i32,
dst_z: i32,
src_width: i32,
src_height: i32,
src_depth: i32,
) {
let gl = &self.raw;
gl.CopyImageSubData(
src_name.0.get(),
src_target,
src_level,
src_x,
src_y,
src_z,
dst_name.0.get(),
dst_target,
dst_level,
dst_x,
dst_y,
dst_z,
src_width,
src_height,
src_depth,
);
}
unsafe fn copy_tex_image_2d(
&self,
target: u32,
level: i32,
internal_format: u32,
x: i32,
y: i32,
width: i32,
height: i32,
border: i32,
) {
let gl = &self.raw;
gl.CopyTexImage2D(target, level, internal_format, x, y, width, height, border);
}
unsafe fn copy_tex_sub_image_2d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
x: i32,
y: i32,
width: i32,
height: i32,
) {
let gl = &self.raw;
gl.CopyTexSubImage2D(target, level, x_offset, y_offset, x, y, width, height);
}
unsafe fn copy_tex_sub_image_3d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
z_offset: i32,
x: i32,
y: i32,
width: i32,
height: i32,
) {
let gl = &self.raw;
gl.CopyTexSubImage3D(
target, level, x_offset, y_offset, z_offset, x, y, width, height,
);
}
unsafe fn delete_buffer(&self, buffer: Self::Buffer) {
let gl = &self.raw;
gl.DeleteBuffers(1, &buffer.0.get());
}
unsafe fn delete_framebuffer(&self, framebuffer: Self::Framebuffer) {
let gl = &self.raw;
gl.DeleteFramebuffers(1, &framebuffer.0.get());
}
unsafe fn delete_query(&self, query: Self::Query) {
let gl = &self.raw;
gl.DeleteQueries(1, &query.0.get());
}
unsafe fn delete_renderbuffer(&self, renderbuffer: Self::Renderbuffer) {
let gl = &self.raw;
gl.DeleteRenderbuffers(1, &renderbuffer.0.get());
}
unsafe fn delete_sampler(&self, sampler: Self::Sampler) {
let gl = &self.raw;
gl.DeleteSamplers(1, &sampler.0.get());
}
unsafe fn delete_sync(&self, fence: Self::Fence) {
let gl = &self.raw;
gl.DeleteSync(fence.0);
}
unsafe fn delete_texture(&self, texture: Self::Texture) {
let gl = &self.raw;
gl.DeleteTextures(1, &texture.0.get());
}
unsafe fn disable(&self, parameter: u32) {
let gl = &self.raw;
gl.Disable(parameter);
}
unsafe fn disable_draw_buffer(&self, parameter: u32, draw_buffer: u32) {
let gl = &self.raw;
gl.Disablei(parameter, draw_buffer);
}
unsafe fn disable_vertex_attrib_array(&self, index: u32) {
let gl = &self.raw;
gl.DisableVertexAttribArray(index);
}
unsafe fn dispatch_compute(&self, groups_x: u32, groups_y: u32, groups_z: u32) {
let gl = &self.raw;
gl.DispatchCompute(groups_x, groups_y, groups_z);
}
unsafe fn dispatch_compute_indirect(&self, offset: i32) {
let gl = &self.raw;
gl.DispatchComputeIndirect(offset as isize);
}
unsafe fn draw_arrays(&self, mode: u32, first: i32, count: i32) {
let gl = &self.raw;
gl.DrawArrays(mode as u32, first, count);
}
unsafe fn draw_arrays_instanced(&self, mode: u32, first: i32, count: i32, instance_count: i32) {
let gl = &self.raw;
gl.DrawArraysInstanced(mode as u32, first, count, instance_count);
}
unsafe fn draw_arrays_instanced_base_instance(
&self,
mode: u32,
first: i32,
count: i32,
instance_count: i32,
base_instance: u32,
) {
let gl = &self.raw;
gl.DrawArraysInstancedBaseInstance(
mode as u32,
first,
count,
instance_count,
base_instance,
);
}
unsafe fn draw_arrays_indirect_offset(&self, mode: u32, offset: i32) {
let gl = &self.raw;
gl.DrawArraysIndirect(mode, offset as *const std::ffi::c_void);
}
unsafe fn draw_buffer(&self, draw_buffer: u32) {
let gl = &self.raw;
gl.DrawBuffer(draw_buffer);
}
unsafe fn draw_buffers(&self, buffers: &[u32]) {
let gl = &self.raw;
gl.DrawBuffers(buffers.len() as i32, buffers.as_ptr());
}
unsafe fn draw_elements(&self, mode: u32, count: i32, element_type: u32, offset: i32) {
let gl = &self.raw;
gl.DrawElements(
mode as u32,
count,
element_type as u32,
offset as *const std::ffi::c_void,
);
}
unsafe fn draw_elements_base_vertex(
&self,
mode: u32,
count: i32,
element_type: u32,
offset: i32,
base_vertex: i32,
) {
let gl = &self.raw;
gl.DrawElementsBaseVertex(
mode as u32,
count,
element_type as u32,
offset as *const std::ffi::c_void,
base_vertex,
);
}
unsafe fn draw_elements_instanced(
&self,
mode: u32,
count: i32,
element_type: u32,
offset: i32,
instance_count: i32,
) {
let gl = &self.raw;
gl.DrawElementsInstanced(
mode as u32,
count,
element_type as u32,
offset as *const std::ffi::c_void,
instance_count,
);
}
unsafe fn draw_elements_instanced_base_vertex(
&self,
mode: u32,
count: i32,
element_type: u32,
offset: i32,
instance_count: i32,
base_vertex: i32,
) {
let gl = &self.raw;
gl.DrawElementsInstancedBaseVertex(
mode as u32,
count,
element_type as u32,
offset as *const std::ffi::c_void,
instance_count,
base_vertex,
);
}
unsafe fn draw_elements_instanced_base_vertex_base_instance(
&self,
mode: u32,
count: i32,
element_type: u32,
offset: i32,
instance_count: i32,
base_vertex: i32,
base_instance: u32,
) {
let gl = &self.raw;
gl.DrawElementsInstancedBaseVertexBaseInstance(
mode as u32,
count,
element_type as u32,
offset as *const std::ffi::c_void,
instance_count,
base_vertex,
base_instance,
);
}
unsafe fn draw_elements_indirect_offset(&self, mode: u32, element_type: u32, offset: i32) {
let gl = &self.raw;
gl.DrawElementsIndirect(mode, element_type, offset as *const std::ffi::c_void);
}
unsafe fn enable(&self, parameter: u32) {
let gl = &self.raw;
gl.Enable(parameter);
}
unsafe fn is_enabled(&self, parameter: u32) -> bool {
let gl = &self.raw;
gl.IsEnabled(parameter) != 0
}
unsafe fn enable_draw_buffer(&self, parameter: u32, draw_buffer: u32) {
let gl = &self.raw;
gl.Enablei(parameter, draw_buffer);
}
unsafe fn enable_vertex_array_attrib(&self, vao: Self::VertexArray, index: u32) {
let gl = &self.raw;
gl.EnableVertexArrayAttrib(vao.0.get(), index);
}
unsafe fn enable_vertex_attrib_array(&self, index: u32) {
let gl = &self.raw;
gl.EnableVertexAttribArray(index);
}
unsafe fn flush(&self) {
let gl = &self.raw;
gl.Flush();
}
unsafe fn framebuffer_renderbuffer(
&self,
target: u32,
attachment: u32,
renderbuffer_target: u32,
renderbuffer: Option<Self::Renderbuffer>,
) {
let gl = &self.raw;
gl.FramebufferRenderbuffer(
target,
attachment,
renderbuffer_target,
renderbuffer.map(|rb| rb.0.get()).unwrap_or(0),
);
}
unsafe fn framebuffer_texture(
&self,
target: u32,
attachment: u32,
texture: Option<Self::Texture>,
level: i32,
) {
let gl = &self.raw;
gl.FramebufferTexture(
target,
attachment,
texture.map(|t| t.0.get()).unwrap_or(0),
level,
);
}
unsafe fn framebuffer_texture_2d(
&self,
target: u32,
attachment: u32,
texture_target: u32,
texture: Option<Self::Texture>,
level: i32,
) {
let gl = &self.raw;
gl.FramebufferTexture2D(
target,
attachment,
texture_target,
texture.map(|t| t.0.get()).unwrap_or(0),
level,
);
}
unsafe fn framebuffer_texture_3d(
&self,
target: u32,
attachment: u32,
texture_target: u32,
texture: Option<Self::Texture>,
level: i32,
layer: i32,
) {
let gl = &self.raw;
gl.FramebufferTexture3D(
target,
attachment,
texture_target,
texture.map(|t| t.0.get()).unwrap_or(0),
level,
layer,
);
}
unsafe fn framebuffer_texture_layer(
&self,
target: u32,
attachment: u32,
texture: Option<Self::Texture>,
level: i32,
layer: i32,
) {
let gl = &self.raw;
gl.FramebufferTextureLayer(
target,
attachment,
texture.map(|t| t.0.get()).unwrap_or(0),
level,
layer,
);
}
unsafe fn front_face(&self, value: u32) {
let gl = &self.raw;
gl.FrontFace(value as u32);
}
unsafe fn get_error(&self) -> u32 {
let gl = &self.raw;
gl.GetError()
}
unsafe fn get_tex_parameter_i32(&self, target: u32, parameter: u32) -> i32 {
let gl = &self.raw;
let mut value = 0;
gl.GetTexParameteriv(target, parameter, &mut value);
value
}
unsafe fn get_buffer_parameter_i32(&self, target: u32, parameter: u32) -> i32 {
let gl = &self.raw;
let mut value = 0;
gl.GetBufferParameteriv(target, parameter, &mut value);
value
}
unsafe fn get_parameter_i32(&self, parameter: u32) -> i32 {
let gl = &self.raw;
let mut value = 0;
gl.GetIntegerv(parameter, &mut value);
value
}
unsafe fn get_parameter_i32_slice(&self, parameter: u32, out: &mut [i32]) {
let gl = &self.raw;
gl.GetIntegerv(parameter, &mut out[0]);
}
unsafe fn get_parameter_f32(&self, parameter: u32) -> f32 {
let gl = &self.raw;
let mut value: f32 = 0.0;
gl.GetFloatv(parameter, &mut value);
value
}
unsafe fn get_parameter_f32_slice(&self, parameter: u32, out: &mut [f32]) {
let gl = &self.raw;
gl.GetFloatv(parameter, &mut out[0]);
}
unsafe fn get_parameter_indexed_i32(&self, parameter: u32, index: u32) -> i32 {
let gl = &self.raw;
let mut value = 0;
gl.GetIntegeri_v(parameter, index, &mut value);
value
}
unsafe fn get_parameter_indexed_string(&self, parameter: u32, index: u32) -> String {
let gl = &self.raw;
let raw_ptr = gl.GetStringi(parameter, index);
std::ffi::CStr::from_ptr(raw_ptr as *const native_gl::GLchar)
.to_str()
.unwrap()
.to_owned()
}
unsafe fn get_parameter_string(&self, parameter: u32) -> String {
let gl = &self.raw;
let raw_ptr = gl.GetString(parameter);
if raw_ptr.is_null() {
panic!(
"Get parameter string 0x{:X} failed. Maybe your GL context version is too outdated.",
parameter
)
}
std::ffi::CStr::from_ptr(raw_ptr as *const native_gl::GLchar)
.to_str()
.unwrap()
.to_owned()
}
unsafe fn get_uniform_location(
&self,
program: Self::Program,
name: &str,
) -> Option<Self::UniformLocation> {
let gl = &self.raw;
let name = CString::new(name).unwrap();
let uniform_location =
gl.GetUniformLocation(program.0.get(), name.as_ptr() as *const native_gl::GLchar);
if uniform_location < 0 {
None
} else {
Some(NativeUniformLocation(uniform_location as u32))
}
}
unsafe fn get_attrib_location(&self, program: Self::Program, name: &str) -> Option<u32> {
let gl = &self.raw;
let name = CString::new(name).unwrap();
let attrib_location =
gl.GetAttribLocation(program.0.get(), name.as_ptr() as *const native_gl::GLchar);
if attrib_location < 0 {
None
} else {
Some(attrib_location as u32)
}
}
unsafe fn bind_attrib_location(&self, program: Self::Program, index: u32, name: &str) {
let gl = &self.raw;
let name = CString::new(name).unwrap();
gl.BindAttribLocation(
program.0.get(),
index,
name.as_ptr() as *const native_gl::GLchar,
);
}
unsafe fn get_active_attributes(&self, program: Self::Program) -> u32 {
let gl = &self.raw;
let mut count = 0;
gl.GetProgramiv(program.0.get(), ACTIVE_ATTRIBUTES, &mut count);
count as u32
}
unsafe fn get_active_attribute(
&self,
program: Self::Program,
index: u32,
) -> Option<ActiveAttribute> {
let gl = &self.raw;
let mut attribute_max_size = 0;
gl.GetProgramiv(
program.0.get(),
ACTIVE_ATTRIBUTE_MAX_LENGTH,
&mut attribute_max_size,
);
let mut name = String::with_capacity(attribute_max_size as usize);
name.extend(std::iter::repeat('\0').take(attribute_max_size as usize));
let mut length = 0;
let mut size = 0;
let mut atype = 0;
gl.GetActiveAttrib(
program.0.get(),
index,
attribute_max_size,
&mut length,
&mut size,
&mut atype,
name.as_ptr() as *mut native_gl::GLchar,
);
name.truncate(length as usize);
Some(ActiveAttribute { name, size, atype })
}
unsafe fn get_sync_status(&self, fence: Self::Fence) -> u32 {
let gl = &self.raw;
let mut len = 0;
let mut values = [UNSIGNALED as i32];
gl.GetSynciv(
fence.0,
SYNC_STATUS,
values.len() as i32,
&mut len,
values.as_mut_ptr(),
);
values[0] as u32
}
unsafe fn is_sync(&self, fence: Self::Fence) -> bool {
let gl = &self.raw;
1 == gl.IsSync(fence.0)
}
unsafe fn renderbuffer_storage(
&self,
target: u32,
internal_format: u32,
width: i32,
height: i32,
) {
let gl = &self.raw;
gl.RenderbufferStorage(target, internal_format, width, height);
}
unsafe fn renderbuffer_storage_multisample(
&self,
target: u32,
samples: i32,
internal_format: u32,
width: i32,
height: i32,
) {
let gl = &self.raw;
gl.RenderbufferStorageMultisample(target, samples, internal_format, width, height);
}
unsafe fn sampler_parameter_f32(&self, sampler: Self::Sampler, name: u32, value: f32) {
let gl = &self.raw;
gl.SamplerParameterf(sampler.0.get(), name, value);
}
unsafe fn sampler_parameter_f32_slice(&self, sampler: Self::Sampler, name: u32, value: &[f32]) {
let gl = &self.raw;
gl.SamplerParameterfv(sampler.0.get(), name, value.as_ptr());
}
unsafe fn sampler_parameter_i32(&self, sampler: Self::Sampler, name: u32, value: i32) {
let gl = &self.raw;
gl.SamplerParameteri(sampler.0.get(), name, value);
}
unsafe fn generate_mipmap(&self, target: u32) {
let gl = &self.raw;
gl.GenerateMipmap(target);
}
unsafe fn generate_texture_mipmap(&self, texture: Self::Texture) {
let gl = &self.raw;
gl.GenerateTextureMipmap(texture.0.get());
}
unsafe fn tex_image_1d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
border: i32,
format: u32,
ty: u32,
pixels: Option<&[u8]>,
) {
let gl = &self.raw;
gl.TexImage1D(
target,
level,
internal_format,
width,
border,
format,
ty,
pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void,
);
}
unsafe fn compressed_tex_image_1d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
border: i32,
image_size: i32,
pixels: &[u8],
) {
let gl = &self.raw;
gl.CompressedTexImage1D(
target,
level,
internal_format as u32,
width,
border,
image_size,
pixels.as_ptr() as *const std::ffi::c_void,
);
}
unsafe fn tex_image_2d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
height: i32,
border: i32,
format: u32,
ty: u32,
pixels: Option<&[u8]>,
) {
let gl = &self.raw;
gl.TexImage2D(
target,
level,
internal_format,
width,
height,
border,
format,
ty,
pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void,
);
}
unsafe fn tex_image_2d_multisample(
&self,
target: u32,
samples: i32,
internal_format: i32,
width: i32,
height: i32,
fixed_sample_locations: bool,
) {
let gl = &self.raw;
gl.TexImage2DMultisample(
target,
samples,
internal_format as u32,
width,
height,
if fixed_sample_locations { 1 } else { 0 },
);
}
unsafe fn compressed_tex_image_2d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
height: i32,
border: i32,
image_size: i32,
pixels: &[u8],
) {
let gl = &self.raw;
gl.CompressedTexImage2D(
target,
level,
internal_format as u32,
width,
height,
border,
image_size,
pixels.as_ptr() as *const std::ffi::c_void,
);
}
unsafe fn tex_image_3d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
height: i32,
depth: i32,
border: i32,
format: u32,
ty: u32,
pixels: Option<&[u8]>,
) {
let gl = &self.raw;
gl.TexImage3D(
target,
level,
internal_format,
width,
height,
depth,
border,
format,
ty,
pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void,
);
}
unsafe fn compressed_tex_image_3d(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
height: i32,
depth: i32,
border: i32,
image_size: i32,
pixels: &[u8],
) {
let gl = &self.raw;
gl.CompressedTexImage3D(
target,
level,
internal_format as u32,
width,
height,
depth,
border,
image_size,
pixels.as_ptr() as *const std::ffi::c_void,
);
}
unsafe fn tex_storage_1d(&self, target: u32, levels: i32, internal_format: u32, width: i32) {
let gl = &self.raw;
gl.TexStorage1D(target, levels, internal_format, width);
}
unsafe fn tex_storage_2d(
&self,
target: u32,
levels: i32,
internal_format: u32,
width: i32,
height: i32,
) {
let gl = &self.raw;
gl.TexStorage2D(target, levels, internal_format, width, height);
}
unsafe fn tex_storage_2d_multisample(
&self,
target: u32,
samples: i32,
internal_format: u32,
width: i32,
height: i32,
fixed_sample_locations: bool,
) {
let gl = &self.raw;
gl.TexStorage2DMultisample(
target,
samples,
internal_format,
width,
height,
if fixed_sample_locations { 1 } else { 0 },
);
}
unsafe fn tex_storage_3d(
&self,
target: u32,
levels: i32,
internal_format: u32,
width: i32,
height: i32,
depth: i32,
) {
let gl = &self.raw;
gl.TexStorage3D(target, levels, internal_format, width, height, depth);
}
unsafe fn texture_storage_3d(
&self,
texture: Self::Texture,
levels: i32,
internal_format: u32,
width: i32,
height: i32,
depth: i32,
) {
let gl = &self.raw;
gl.TextureStorage3D(
texture.0.get(),
levels,
internal_format,
width,
height,
depth,
);
}
unsafe fn get_uniform_i32(
&self,
program: Self::Program,
location: &Self::UniformLocation,
v: &mut [i32],
) {
let gl = &self.raw;
gl.GetUniformiv(
program.0.get() as u32,
location.0 as i32,
v.as_mut_ptr() as *mut i32,
)
}
unsafe fn get_uniform_f32(
&self,
program: Self::Program,
location: &Self::UniformLocation,
v: &mut [f32],
) {
let gl = &self.raw;
gl.GetUniformfv(
program.0.get() as u32,
location.0 as i32,
v.as_mut_ptr() as *mut f32,
)
}
unsafe fn uniform_1_i32(&self, location: Option<&Self::UniformLocation>, x: i32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1i(loc.0 as i32, x);
}
}
unsafe fn uniform_2_i32(&self, location: Option<&Self::UniformLocation>, x: i32, y: i32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2i(loc.0 as i32, x, y);
}
}
unsafe fn uniform_3_i32(
&self,
location: Option<&Self::UniformLocation>,
x: i32,
y: i32,
z: i32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3i(loc.0 as i32, x, y, z);
}
}
unsafe fn uniform_4_i32(
&self,
location: Option<&Self::UniformLocation>,
x: i32,
y: i32,
z: i32,
w: i32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4i(loc.0 as i32, x, y, z, w);
}
}
unsafe fn uniform_1_i32_slice(&self, location: Option<&Self::UniformLocation>, v: &[i32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1iv(loc.0 as i32, v.len() as i32, v.as_ptr());
}
}
unsafe fn uniform_2_i32_slice(&self, location: Option<&Self::UniformLocation>, v: &[i32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2iv(loc.0 as i32, v.len() as i32 / 2, v.as_ptr());
}
}
unsafe fn uniform_3_i32_slice(&self, location: Option<&Self::UniformLocation>, v: &[i32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3iv(loc.0 as i32, v.len() as i32 / 3, v.as_ptr());
}
}
unsafe fn uniform_4_i32_slice(&self, location: Option<&Self::UniformLocation>, v: &[i32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4iv(loc.0 as i32, v.len() as i32 / 4, v.as_ptr());
}
}
unsafe fn uniform_1_u32(&self, location: Option<&Self::UniformLocation>, x: u32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1ui(loc.0 as i32, x);
}
}
unsafe fn uniform_2_u32(&self, location: Option<&Self::UniformLocation>, x: u32, y: u32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2ui(loc.0 as i32, x, y);
}
}
unsafe fn uniform_3_u32(
&self,
location: Option<&Self::UniformLocation>,
x: u32,
y: u32,
z: u32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3ui(loc.0 as i32, x, y, z);
}
}
unsafe fn uniform_4_u32(
&self,
location: Option<&Self::UniformLocation>,
x: u32,
y: u32,
z: u32,
w: u32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4ui(loc.0 as i32, x, y, z, w);
}
}
unsafe fn uniform_1_u32_slice(&self, location: Option<&Self::UniformLocation>, v: &[u32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1uiv(loc.0 as i32, v.len() as i32, v.as_ptr());
}
}
unsafe fn uniform_2_u32_slice(&self, location: Option<&Self::UniformLocation>, v: &[u32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2uiv(loc.0 as i32, v.len() as i32 / 2, v.as_ptr());
}
}
unsafe fn uniform_3_u32_slice(&self, location: Option<&Self::UniformLocation>, v: &[u32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3uiv(loc.0 as i32, v.len() as i32 / 3, v.as_ptr());
}
}
unsafe fn uniform_4_u32_slice(&self, location: Option<&Self::UniformLocation>, v: &[u32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4uiv(loc.0 as i32, v.len() as i32 / 4, v.as_ptr());
}
}
unsafe fn uniform_1_f32(&self, location: Option<&Self::UniformLocation>, x: f32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1f(loc.0 as i32, x);
}
}
unsafe fn uniform_2_f32(&self, location: Option<&Self::UniformLocation>, x: f32, y: f32) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2f(loc.0 as i32, x, y);
}
}
unsafe fn uniform_3_f32(
&self,
location: Option<&Self::UniformLocation>,
x: f32,
y: f32,
z: f32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3f(loc.0 as i32, x, y, z);
}
}
unsafe fn uniform_4_f32(
&self,
location: Option<&Self::UniformLocation>,
x: f32,
y: f32,
z: f32,
w: f32,
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4f(loc.0 as i32, x, y, z, w);
}
}
unsafe fn uniform_1_f32_slice(&self, location: Option<&Self::UniformLocation>, v: &[f32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform1fv(loc.0 as i32, v.len() as i32, v.as_ptr());
}
}
unsafe fn uniform_2_f32_slice(&self, location: Option<&Self::UniformLocation>, v: &[f32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform2fv(loc.0 as i32, v.len() as i32 / 2, v.as_ptr());
}
}
unsafe fn uniform_3_f32_slice(&self, location: Option<&Self::UniformLocation>, v: &[f32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform3fv(loc.0 as i32, v.len() as i32 / 3, v.as_ptr());
}
}
unsafe fn uniform_4_f32_slice(&self, location: Option<&Self::UniformLocation>, v: &[f32]) {
let gl = &self.raw;
if let Some(loc) = location {
gl.Uniform4fv(loc.0 as i32, v.len() as i32 / 4, v.as_ptr());
}
}
unsafe fn uniform_matrix_2_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix2fv(
loc.0 as i32,
v.len() as i32 / 4,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_2x3_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix2x3fv(
loc.0 as i32,
v.len() as i32 / 6,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_2x4_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix2x4fv(
loc.0 as i32,
v.len() as i32 / 8,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_3x2_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix3x2fv(
loc.0 as i32,
v.len() as i32 / 6,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_3_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix3fv(
loc.0 as i32,
v.len() as i32 / 9,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_3x4_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix3x4fv(
loc.0 as i32,
v.len() as i32 / 12,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_4x2_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix4x2fv(
loc.0 as i32,
v.len() as i32 / 8,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_4x3_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix4x3fv(
loc.0 as i32,
v.len() as i32 / 12,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn uniform_matrix_4_f32_slice(
&self,
location: Option<&Self::UniformLocation>,
transpose: bool,
v: &[f32],
) {
let gl = &self.raw;
if let Some(loc) = location {
gl.UniformMatrix4fv(
loc.0 as i32,
v.len() as i32 / 16,
transpose as u8,
v.as_ptr(),
);
}
}
unsafe fn unmap_buffer(&self, target: u32) {
let gl = &self.raw;
gl.UnmapBuffer(target);
}
unsafe fn cull_face(&self, value: u32) {
let gl = &self.raw;
gl.CullFace(value as u32);
}
unsafe fn color_mask(&self, red: bool, green: bool, blue: bool, alpha: bool) {
let gl = &self.raw;
gl.ColorMask(red as u8, green as u8, blue as u8, alpha as u8);
}
unsafe fn color_mask_draw_buffer(
&self,
draw_buffer: u32,
red: bool,
green: bool,
blue: bool,
alpha: bool,
) {
let gl = &self.raw;
gl.ColorMaski(draw_buffer, red as u8, green as u8, blue as u8, alpha as u8);
}
unsafe fn depth_mask(&self, value: bool) {
let gl = &self.raw;
gl.DepthMask(value as u8);
}
unsafe fn blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) {
let gl = &self.raw;
gl.BlendColor(red, green, blue, alpha);
}
unsafe fn line_width(&self, width: f32) {
let gl = &self.raw;
gl.LineWidth(width);
}
unsafe fn map_buffer_range(
&self,
target: u32,
offset: i32,
length: i32,
access: u32,
) -> *mut u8 {
let gl = &self.raw;
gl.MapBufferRange(target, offset as isize, length as isize, access) as *mut u8
}
unsafe fn flush_mapped_buffer_range(&self, target: u32, offset: i32, length: i32) {
let gl = &self.raw;
gl.FlushMappedBufferRange(target, offset as isize, length as isize)
}
unsafe fn invalidate_buffer_sub_data(&self, target: u32, offset: i32, length: i32) {
let gl = &self.raw;
gl.InvalidateBufferSubData(target, offset as isize, length as isize)
}
unsafe fn invalidate_framebuffer(&self, target: u32, attachments: &[u32]) {
let gl = &self.raw;
gl.InvalidateFramebuffer(target, attachments.len() as i32, attachments.as_ptr());
}
unsafe fn polygon_offset(&self, factor: f32, units: f32) {
let gl = &self.raw;
gl.PolygonOffset(factor, units);
}
unsafe fn polygon_mode(&self, face: u32, mode: u32) {
let gl = &self.raw;
gl.PolygonMode(face as u32, mode as u32);
}
unsafe fn finish(&self) {
let gl = &self.raw;
gl.Finish();
}
unsafe fn bind_texture(&self, target: u32, texture: Option<Self::Texture>) {
let gl = &self.raw;
gl.BindTexture(target, texture.map(|t| t.0.get()).unwrap_or(0));
}
unsafe fn bind_sampler(&self, unit: u32, sampler: Option<Self::Sampler>) {
let gl = &self.raw;
gl.BindSampler(unit, sampler.map(|s| s.0.get()).unwrap_or(0));
}
unsafe fn active_texture(&self, unit: u32) {
let gl = &self.raw;
gl.ActiveTexture(unit);
}
unsafe fn fence_sync(&self, condition: u32, flags: u32) -> Result<Self::Fence, String> {
let gl = &self.raw;
Ok(NativeFence(gl.FenceSync(condition as u32, flags)))
}
unsafe fn tex_parameter_f32(&self, target: u32, parameter: u32, value: f32) {
let gl = &self.raw;
gl.TexParameterf(target, parameter, value);
}
unsafe fn tex_parameter_i32(&self, target: u32, parameter: u32, value: i32) {
let gl = &self.raw;
gl.TexParameteri(target, parameter, value);
}
unsafe fn texture_parameter_i32(&self, texture: Self::Texture, parameter: u32, value: i32) {
let gl = &self.raw;
gl.TextureParameteri(texture.0.get(), parameter, value);
}
unsafe fn tex_parameter_f32_slice(&self, target: u32, parameter: u32, values: &[f32]) {
let gl = &self.raw;
gl.TexParameterfv(target, parameter, values.as_ptr());
}
unsafe fn tex_parameter_i32_slice(&self, target: u32, parameter: u32, values: &[i32]) {
let gl = &self.raw;
gl.TexParameteriv(target, parameter, values.as_ptr());
}
unsafe fn tex_sub_image_2d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
width: i32,
height: i32,
format: u32,
ty: u32,
pixels: PixelUnpackData,
) {
let gl = &self.raw;
gl.TexSubImage2D(
target,
level,
x_offset,
y_offset,
width,
height,
format,
ty,
match pixels {
PixelUnpackData::BufferOffset(offset) => offset as *const std::ffi::c_void,
PixelUnpackData::Slice(data) => data.as_ptr() as *const std::ffi::c_void,
},
);
}
unsafe fn compressed_tex_sub_image_2d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
width: i32,
height: i32,
format: u32,
pixels: CompressedPixelUnpackData,
) {
let gl = &self.raw;
let (data, image_size) = match pixels {
CompressedPixelUnpackData::BufferRange(ref range) => (
range.start as *const std::ffi::c_void,
(range.end - range.start) as i32,
),
CompressedPixelUnpackData::Slice(data) => {
(data.as_ptr() as *const std::ffi::c_void, data.len() as i32)
}
};
gl.CompressedTexSubImage2D(
target, level, x_offset, y_offset, width, height, format, image_size, data,
);
}
unsafe fn tex_sub_image_3d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
z_offset: i32,
width: i32,
height: i32,
depth: i32,
format: u32,
ty: u32,
pixels: PixelUnpackData,
) {
let gl = &self.raw;
gl.TexSubImage3D(
target,
level,
x_offset,
y_offset,
z_offset,
width,
height,
depth,
format,
ty,
match pixels {
PixelUnpackData::BufferOffset(offset) => offset as *const std::ffi::c_void,
PixelUnpackData::Slice(data) => data.as_ptr() as *const std::ffi::c_void,
},
);
}
unsafe fn texture_sub_image_3d(
&self,
texture: Self::Texture,
level: i32,
x_offset: i32,
y_offset: i32,
z_offset: i32,
width: i32,
height: i32,
depth: i32,
format: u32,
ty: u32,
pixels: PixelUnpackData,
) {
let gl = &self.raw;
gl.TextureSubImage3D(
texture.0.get(),
level,
x_offset,
y_offset,
z_offset,
width,
height,
depth,
format,
ty,
match pixels {
PixelUnpackData::BufferOffset(offset) => offset as *const std::ffi::c_void,
PixelUnpackData::Slice(data) => data.as_ptr() as *const std::ffi::c_void,
},
);
}
unsafe fn compressed_tex_sub_image_3d(
&self,
target: u32,
level: i32,
x_offset: i32,
y_offset: i32,
z_offset: i32,
width: i32,
height: i32,
depth: i32,
format: u32,
pixels: CompressedPixelUnpackData,
) {
let gl = &self.raw;
let (data, image_size) = match pixels {
CompressedPixelUnpackData::BufferRange(ref range) => (
range.start as *const std::ffi::c_void,
(range.end - range.start) as i32,
),
CompressedPixelUnpackData::Slice(data) => {
(data.as_ptr() as *const std::ffi::c_void, data.len() as i32)
}
};
gl.CompressedTexSubImage3D(
target, level, x_offset, y_offset, z_offset, width, height, depth, format, image_size,
data,
);
}
unsafe fn depth_func(&self, func: u32) {
let gl = &self.raw;
gl.DepthFunc(func as u32);
}
unsafe fn depth_range_f32(&self, near: f32, far: f32) {
let gl = &self.raw;
gl.DepthRangef(near, far);
}
unsafe fn depth_range_f64(&self, near: f64, far: f64) {
let gl = &self.raw;
gl.DepthRange(near, far);
}
unsafe fn depth_range_f64_slice(&self, first: u32, count: i32, values: &[[f64; 2]]) {
let gl = &self.raw;
gl.DepthRangeArrayv(first, count, values.as_ptr() as *const f64);
}
unsafe fn scissor(&self, x: i32, y: i32, width: i32, height: i32) {
let gl = &self.raw;
gl.Scissor(x, y, width, height);
}
unsafe fn scissor_slice(&self, first: u32, count: i32, scissors: &[[i32; 4]]) {
let gl = &self.raw;
gl.ScissorArrayv(first, count, scissors.as_ptr() as *const i32);
}
unsafe fn vertex_array_attrib_binding_f32(
&self,
vao: Self::VertexArray,
index: u32,
binding_index: u32,
) {
let gl = &self.raw;
gl.VertexArrayAttribBinding(vao.0.get(), index, binding_index);
}
unsafe fn vertex_array_attrib_format_f32(
&self,
vao: Self::VertexArray,
index: u32,
size: i32,
data_type: u32,
normalized: bool,
relative_offset: u32,
) {
let gl = &self.raw;
gl.VertexArrayAttribFormat(
vao.0.get(),
index,
size,
data_type,
normalized as u8,
relative_offset,
);
}
unsafe fn vertex_array_attrib_format_i32(
&self,
vao: Self::VertexArray,
index: u32,
size: i32,
data_type: u32,
relative_offset: u32,
) {
let gl = &self.raw;
gl.VertexArrayAttribIFormat(vao.0.get(), index, size, data_type, relative_offset);
}
unsafe fn vertex_array_element_buffer(
&self,
vao: Self::VertexArray,
buffer: Option<Self::Buffer>,
) {
let gl = &self.raw;
gl.VertexArrayElementBuffer(vao.0.get(), buffer.map(|b| b.0.get()).unwrap_or(0));
}
unsafe fn vertex_array_vertex_buffer(
&self,
vao: Self::VertexArray,
binding_index: u32,
buffer: Option<Self::Buffer>,
offset: i32,
stride: i32,
) {
let gl = &self.raw;
gl.VertexArrayVertexBuffer(
vao.0.get(),
binding_index,
buffer.map(|b| b.0.get()).unwrap_or(0),
offset as isize,
stride,
);
}
unsafe fn vertex_attrib_divisor(&self, index: u32, divisor: u32) {
let gl = &self.raw;
gl.VertexAttribDivisor(index, divisor);
}
unsafe fn vertex_attrib_pointer_f32(
&self,
index: u32,
size: i32,
data_type: u32,
normalized: bool,
stride: i32,
offset: i32,
) {
let gl = &self.raw;
gl.VertexAttribPointer(
index,
size,
data_type,
normalized as u8,
stride,
offset as *const std::ffi::c_void,
);
}
unsafe fn vertex_attrib_pointer_i32(
&self,
index: u32,
size: i32,
data_type: u32,
stride: i32,
offset: i32,
) {
let gl = &self.raw;
gl.VertexAttribIPointer(
index,
size,
data_type,
stride,
offset as *const std::ffi::c_void,
);
}
unsafe fn vertex_attrib_pointer_f64(
&self,
index: u32,
size: i32,
data_type: u32,
stride: i32,
offset: i32,
) {
let gl = &self.raw;
gl.VertexAttribLPointer(
index,
size,
data_type,
stride,
offset as *const std::ffi::c_void,
);
}
unsafe fn vertex_attrib_format_f32(
&self,
index: u32,
size: i32,
data_type: u32,
normalized: bool,
relative_offset: u32,
) {
let gl = &self.raw;
gl.VertexAttribFormat(index, size, data_type, normalized as u8, relative_offset);
}
unsafe fn vertex_attrib_format_i32(
&self,
index: u32,
size: i32,
data_type: u32,
relative_offset: u32,
) {
let gl = &self.raw;
gl.VertexAttribIFormat(index, size, data_type, relative_offset);
}
unsafe fn vertex_attrib_1_f32(&self, index: u32, x: f32) {
let gl = &self.raw;
gl.VertexAttrib1f(index, x);
}
unsafe fn vertex_attrib_2_f32(&self, index: u32, x: f32, y: f32) {
let gl = &self.raw;
gl.VertexAttrib2f(index, x, y);
}
unsafe fn vertex_attrib_3_f32(&self, index: u32, x: f32, y: f32, z: f32) {
let gl = &self.raw;
gl.VertexAttrib3f(index, x, y, z);
}
unsafe fn vertex_attrib_4_f32(&self, index: u32, x: f32, y: f32, z: f32, w: f32) {
let gl = &self.raw;
gl.VertexAttrib4f(index, x, y, z, w);
}
unsafe fn vertex_attrib_1_f32_slice(&self, index: u32, v: &[f32]) {
let gl = &self.raw;
gl.VertexAttrib1fv(index, v.as_ptr());
}
unsafe fn vertex_attrib_2_f32_slice(&self, index: u32, v: &[f32]) {
let gl = &self.raw;
gl.VertexAttrib2fv(index, v.as_ptr());
}
unsafe fn vertex_attrib_3_f32_slice(&self, index: u32, v: &[f32]) {
let gl = &self.raw;
gl.VertexAttrib3fv(index, v.as_ptr());
}
unsafe fn vertex_attrib_4_f32_slice(&self, index: u32, v: &[f32]) {
let gl = &self.raw;
gl.VertexAttrib4fv(index, v.as_ptr());
}
unsafe fn vertex_attrib_binding(&self, attrib_index: u32, binding_index: u32) {
let gl = &self.raw;
gl.VertexAttribBinding(attrib_index, binding_index);
}
unsafe fn vertex_binding_divisor(&self, binding_index: u32, divisor: u32) {
let gl = &self.raw;
gl.VertexBindingDivisor(binding_index, divisor);
}
unsafe fn viewport(&self, x: i32, y: i32, width: i32, height: i32) {
let gl = &self.raw;
gl.Viewport(x, y, width, height);
}
unsafe fn viewport_f32_slice(&self, first: u32, count: i32, values: &[[f32; 4]]) {
let gl = &self.raw;
gl.ViewportArrayv(first, count, values.as_ptr() as *const f32);
}
unsafe fn blend_equation(&self, mode: u32) {
let gl = &self.raw;
gl.BlendEquation(mode as u32);
}
unsafe fn blend_equation_draw_buffer(&self, draw_buffer: u32, mode: u32) {
let gl = &self.raw;
gl.BlendEquationi(draw_buffer, mode as u32);
}
unsafe fn blend_equation_separate(&self, mode_rgb: u32, mode_alpha: u32) {
let gl = &self.raw;
gl.BlendEquationSeparate(mode_rgb as u32, mode_alpha as u32);
}
unsafe fn blend_equation_separate_draw_buffer(
&self,
draw_buffer: u32,
mode_rgb: u32,
mode_alpha: u32,
) {
let gl = &self.raw;
gl.BlendEquationSeparatei(draw_buffer, mode_rgb as u32, mode_alpha as u32);
}
unsafe fn blend_func(&self, src: u32, dst: u32) {
let gl = &self.raw;
gl.BlendFunc(src as u32, dst as u32);
}
unsafe fn blend_func_draw_buffer(&self, draw_buffer: u32, src: u32, dst: u32) {
let gl = &self.raw;
gl.BlendFunci(draw_buffer, src as u32, dst as u32);
}
unsafe fn blend_func_separate(
&self,
src_rgb: u32,
dst_rgb: u32,
src_alpha: u32,
dst_alpha: u32,
) {
let gl = &self.raw;
gl.BlendFuncSeparate(
src_rgb as u32,
dst_rgb as u32,
src_alpha as u32,
dst_alpha as u32,
);
}
unsafe fn blend_func_separate_draw_buffer(
&self,
draw_buffer: u32,
src_rgb: u32,
dst_rgb: u32,
src_alpha: u32,
dst_alpha: u32,
) {
let gl = &self.raw;
gl.BlendFuncSeparatei(
draw_buffer,
src_rgb as u32,
dst_rgb as u32,
src_alpha as u32,
dst_alpha as u32,
);
}
unsafe fn stencil_func(&self, func: u32, reference: i32, mask: u32) {
let gl = &self.raw;
gl.StencilFunc(func as u32, reference, mask);
}
unsafe fn stencil_func_separate(&self, face: u32, func: u32, reference: i32, mask: u32) {
let gl = &self.raw;
gl.StencilFuncSeparate(face as u32, func as u32, reference, mask);
}
unsafe fn stencil_mask(&self, mask: u32) {
let gl = &self.raw;
gl.StencilMask(mask);
}
unsafe fn stencil_mask_separate(&self, face: u32, mask: u32) {
let gl = &self.raw;
gl.StencilMaskSeparate(face as u32, mask);
}
unsafe fn stencil_op(&self, stencil_fail: u32, depth_fail: u32, pass: u32) {
let gl = &self.raw;
gl.StencilOp(stencil_fail as u32, depth_fail as u32, pass as u32);
}
unsafe fn stencil_op_separate(&self, face: u32, stencil_fail: u32, depth_fail: u32, pass: u32) {
let gl = &self.raw;
gl.StencilOpSeparate(
face as u32,
stencil_fail as u32,
depth_fail as u32,
pass as u32,
);
}
unsafe fn debug_message_control(
&self,
source: u32,
msg_type: u32,
severity: u32,
ids: &[u32],
enabled: bool,
) {
let gl = &self.raw;
let ids_ptr = if ids.is_empty() {
std::ptr::null()
} else {
ids.as_ptr()
};
gl.DebugMessageControl(
source,
msg_type,
severity,
ids.len() as i32,
ids_ptr,
enabled as u8,
);
}
unsafe fn debug_message_insert<S>(
&self,
source: u32,
msg_type: u32,
id: u32,
severity: u32,
msg: S,
) where
S: AsRef<str>,
{
let gl = &self.raw;
let message = msg.as_ref().as_bytes();
let length = message.len() as i32;
gl.DebugMessageInsert(
source,
msg_type,
id,
severity,
length,
message.as_ptr() as *const native_gl::GLchar,
);
}
unsafe fn debug_message_callback<F>(&mut self, callback: F)
where
F: FnMut(u32, u32, u32, u32, &str) + 'static,
{
match self.debug_callback {
Some(_) => {
panic!("Debug callback already set");
}
None => {
let trait_object: DebugCallback = Box::new(callback);
let thin_ptr = Box::new(trait_object);
let raw_ptr = Box::into_raw(thin_ptr) as *mut _ as *mut std::ffi::c_void;
let gl = &self.raw;
if gl.DebugMessageCallback_is_loaded() {
gl.DebugMessageCallback(Some(raw_debug_message_callback), raw_ptr);
} else {
gl.DebugMessageCallbackKHR(Some(raw_debug_message_callback), raw_ptr);
}
self.debug_callback = Some(DebugCallbackRawPtr { callback: raw_ptr });
}
}
}
unsafe fn get_debug_message_log(&self, count: u32) -> Vec<DebugMessageLogEntry> {
let ct = count as usize;
let mut sources = Vec::with_capacity(ct);
let mut types = Vec::with_capacity(ct);
let mut ids = Vec::with_capacity(ct);
let mut severities = Vec::with_capacity(ct);
let mut lengths = Vec::with_capacity(ct);
let buf_size = (count * MAX_DEBUG_MESSAGE_LENGTH) as i32;
let mut message_log = Vec::with_capacity(buf_size as usize);
let gl = &self.raw;
let received = gl.GetDebugMessageLog(
count,
buf_size,
sources.as_mut_ptr(),
types.as_mut_ptr(),
ids.as_mut_ptr(),
severities.as_mut_ptr(),
lengths.as_mut_ptr(),
message_log.as_mut_ptr(),
) as usize;
sources.set_len(received);
types.set_len(received);
ids.set_len(received);
severities.set_len(received);
lengths.set_len(received);
message_log.set_len(buf_size as usize);
let mut entries = Vec::new();
let mut offset = 0;
for i in 0..received {
let message =
std::ffi::CStr::from_ptr(message_log[offset..].as_ptr()).to_string_lossy();
offset += lengths[i] as usize;
entries.push(DebugMessageLogEntry {
source: sources[i],
msg_type: types[i],
id: ids[i],
severity: severities[i],
message: message.to_string(),
});
}
entries
}
unsafe fn push_debug_group<S>(&self, source: u32, id: u32, message: S)
where
S: AsRef<str>,
{
let gl = &self.raw;
let msg = message.as_ref().as_bytes();
let length = msg.len() as i32;
gl.PushDebugGroup(source, id, length, msg.as_ptr() as *const native_gl::GLchar);
}
unsafe fn pop_debug_group(&self) {
let gl = &self.raw;
gl.PopDebugGroup();
}
unsafe fn object_label<S>(&self, identifier: u32, name: u32, label: Option<S>)
where
S: AsRef<str>,
{
let gl = &self.raw;
match label {
Some(l) => {
let lbl = l.as_ref().as_bytes();
let length = lbl.len() as i32;
gl.ObjectLabel(
identifier,
name,
length,
lbl.as_ptr() as *const native_gl::GLchar,
);
}
None => gl.ObjectLabel(identifier, name, 0, std::ptr::null()),
}
}
unsafe fn get_object_label(&self, identifier: u32, name: u32) -> String {
let gl = &self.raw;
let mut len = 0;
let mut label_buf = Vec::with_capacity(self.constants.max_label_length as usize);
gl.GetObjectLabel(
identifier,
name,
self.constants.max_label_length,
&mut len,
label_buf.as_mut_ptr(),
);
label_buf.set_len(len as usize);
std::ffi::CStr::from_ptr(label_buf.as_ptr())
.to_str()
.unwrap()
.to_owned()
}
unsafe fn object_ptr_label<S>(&self, sync: Self::Fence, label: Option<S>)
where
S: AsRef<str>,
{
let gl = &self.raw;
match label {
Some(l) => {
let lbl = l.as_ref().as_bytes();
let length = lbl.len() as i32;
gl.ObjectPtrLabel(
sync.0 as *mut std::ffi::c_void,
length,
lbl.as_ptr() as *const native_gl::GLchar,
);
}
None => gl.ObjectPtrLabel(sync.0 as *mut std::ffi::c_void, 0, std::ptr::null()),
}
}
unsafe fn get_object_ptr_label(&self, sync: Self::Fence) -> String {
let gl = &self.raw;
let mut len = 0;
let mut label_buf = Vec::with_capacity(self.constants.max_label_length as usize);
gl.GetObjectPtrLabel(
sync.0 as *mut std::ffi::c_void,
self.constants.max_label_length,
&mut len,
label_buf.as_mut_ptr(),
);
label_buf.set_len(len as usize);
std::ffi::CStr::from_ptr(label_buf.as_ptr())
.to_str()
.unwrap()
.to_owned()
}
unsafe fn get_uniform_block_index(&self, program: Self::Program, name: &str) -> Option<u32> {
let gl = &self.raw;
let name = CString::new(name).unwrap();
let index = gl.GetUniformBlockIndex(program.0.get(), name.as_ptr());
if index == INVALID_INDEX {
None
} else {
Some(index)
}
}
unsafe fn uniform_block_binding(&self, program: Self::Program, index: u32, binding: u32) {
let gl = &self.raw;
gl.UniformBlockBinding(program.0.get(), index, binding);
}
unsafe fn get_shader_storage_block_index(
&self,
program: Self::Program,
name: &str,
) -> Option<u32> {
let gl = &self.raw;
let name = CString::new(name).unwrap();
let index =
gl.GetProgramResourceIndex(program.0.get(), SHADER_STORAGE_BLOCK, name.as_ptr());
if index == INVALID_INDEX {
None
} else {
Some(index)
}
}
unsafe fn shader_storage_block_binding(
&self,
program: Self::Program,
index: u32,
binding: u32,
) {
let gl = &self.raw;
gl.ShaderStorageBlockBinding(program.0.get(), index, binding);
}
unsafe fn read_buffer(&self, src: u32) {
let gl = &self.raw;
gl.ReadBuffer(src);
}
unsafe fn read_pixels(
&self,
x: i32,
y: i32,
width: i32,
height: i32,
format: u32,
gltype: u32,
pixels: PixelPackData,
) {
let gl = &self.raw;
gl.ReadPixels(
x,
y,
width,
height,
format,
gltype,
match pixels {
PixelPackData::BufferOffset(offset) => offset as *mut std::ffi::c_void,
PixelPackData::Slice(data) => data.as_mut_ptr() as *mut std::ffi::c_void,
},
);
}
unsafe fn begin_query(&self, target: u32, query: Self::Query) {
let gl = &self.raw;
gl.BeginQuery(target, query.0.get());
}
unsafe fn end_query(&self, target: u32) {
let gl = &self.raw;
gl.EndQuery(target);
}
unsafe fn query_counter(&self, query: Self::Query, target: u32) {
let gl = &self.raw;
gl.QueryCounter(query.0.get(), target);
}
unsafe fn get_query_parameter_u32(&self, query: Self::Query, parameter: u32) -> u32 {
let gl = &self.raw;
let mut value = 0;
gl.GetQueryObjectuiv(query.0.get(), parameter, &mut value);
value
}
unsafe fn get_query_parameter_u64_with_offset(
&self,
query: Self::Query,
parameter: u32,
offset: usize,
) {
let gl = &self.raw;
gl.GetQueryObjectui64v(query.0.get(), parameter, offset as *mut _);
}
unsafe fn create_transform_feedback(&self) -> Result<Self::TransformFeedback, String> {
let gl = &self.raw;
let mut name = 0;
gl.GenTransformFeedbacks(1, &mut name);
Ok(NativeTransformFeedback(non_zero_gl_name(name)))
}
unsafe fn delete_transform_feedback(&self, transform_feedback: Self::TransformFeedback) {
let gl = &self.raw;
gl.DeleteTransformFeedbacks(1, &transform_feedback.0.get());
}
unsafe fn bind_transform_feedback(
&self,
target: u32,
transform_feedback: Option<Self::TransformFeedback>,
) {
let gl = &self.raw;
gl.BindTransformFeedback(target, transform_feedback.map(|tf| tf.0.get()).unwrap_or(0));
}
unsafe fn begin_transform_feedback(&self, primitive_mode: u32) {
let gl = &self.raw;
gl.BeginTransformFeedback(primitive_mode);
}
unsafe fn end_transform_feedback(&self) {
let gl = &self.raw;
gl.EndTransformFeedback();
}
unsafe fn pause_transform_feedback(&self) {
let gl = &self.raw;
gl.PauseTransformFeedback();
}
unsafe fn resume_transform_feedback(&self) {
let gl = &self.raw;
gl.ResumeTransformFeedback();
}
unsafe fn transform_feedback_varyings(
&self,
program: Self::Program,
varyings: &[&str],
buffer_mode: u32,
) {
let gl = &self.raw;
let strings: Vec<CString> = varyings
.iter()
.copied()
.map(CString::new)
.collect::<Result<_, _>>()
.unwrap();
let varyings: Vec<_> = strings.iter().map(|c_str| c_str.as_ptr()).collect();
gl.TransformFeedbackVaryings(
program.0.get(),
varyings.len() as i32,
varyings.as_ptr(),
buffer_mode,
);
}
unsafe fn get_transform_feedback_varying(
&self,
program: Self::Program,
index: u32,
) -> Option<ActiveTransformFeedback> {
let gl = &self.raw;
const buf_size: usize = 256;
const bytes: [u8; buf_size] = [0; buf_size];
let size: i32 = 0;
let tftype: u32 = 0;
let c_name = CString::new(bytes.to_vec()).unwrap();
let c_name_buf = c_name.into_raw();
gl.GetTransformFeedbackVarying(
program.0.get(),
index,
buf_size as i32,
std::ptr::null_mut(),
size as *mut i32,
tftype as *mut u32,
c_name_buf,
);
let name = CString::from_raw(c_name_buf).into_string().unwrap();
Some(ActiveTransformFeedback { size, tftype, name })
}
unsafe fn memory_barrier(&self, barriers: u32) {
let gl = &self.raw;
gl.MemoryBarrier(barriers);
}
unsafe fn memory_barrier_by_region(&self, barriers: u32) {
let gl = &self.raw;
gl.MemoryBarrierByRegion(barriers);
}
unsafe fn bind_image_texture(
&self,
unit: u32,
texture: Self::Texture,
level: i32,
layered: bool,
layer: i32,
access: u32,
format: u32,
) {
let gl = &self.raw;
gl.BindImageTexture(
unit,
texture.0.get(),
level,
layered as u8,
layer,
access,
format,
);
}
unsafe fn get_active_uniform_block_parameter_i32(
&self,
program: Self::Program,
uniform_block_index: u32,
parameter: u32,
) -> i32 {
let gl = &self.raw;
let mut value = 0;
gl.GetActiveUniformBlockiv(program.0.get(), uniform_block_index, parameter, &mut value);
value
}
unsafe fn get_active_uniform_block_parameter_i32_slice(
&self,
program: Self::Program,
uniform_block_index: u32,
parameter: u32,
out: &mut [i32],
) {
let gl = &self.raw;
gl.GetActiveUniformBlockiv(
program.0.get(),
uniform_block_index,
parameter,
out.as_mut_ptr(),
);
}
unsafe fn get_active_uniform_block_name(
&self,
program: Self::Program,
uniform_block_index: u32,
) -> String {
let gl = &self.raw;
let len = self.get_active_uniform_block_parameter_i32(
program,
uniform_block_index,
crate::UNIFORM_BLOCK_NAME_LENGTH,
);
let len = if gl.GetError() == crate::NO_ERROR && len > 0 {
len as usize
} else {
256
};
let mut buffer = vec![0; len];
let mut length = 0;
gl.GetActiveUniformBlockName(
program.0.get(),
uniform_block_index,
buffer.len() as _,
&mut length,
buffer.as_mut_ptr(),
);
if length > 0 {
assert_eq!(
std::mem::size_of::<u8>(),
std::mem::size_of::<native_gl::GLchar>(),
"This operation is only safe in systems in which the length of \
a GLchar is the same as that of an u8"
);
assert_eq!(
std::mem::align_of::<u8>(),
std::mem::align_of::<native_gl::GLchar>(),
"This operation is only safe in systems in which the alignment \
of a GLchar is the same as that of an u8"
);
let buffer = std::slice::from_raw_parts(
buffer.as_ptr() as *const u8,
(length as usize + 1).min(buffer.len()),
);
let name = CStr::from_bytes_with_nul(&buffer[..])
.unwrap()
.to_str()
.unwrap()
.to_owned();
name
} else {
String::from("")
}
}
unsafe fn max_shader_compiler_threads(&self, count: u32) {
let gl = &self.raw;
if gl.MaxShaderCompilerThreadsKHR_is_loaded() {
gl.MaxShaderCompilerThreadsKHR(count);
} else {
gl.MaxShaderCompilerThreadsARB(count);
}
}
}
extern "system" fn raw_debug_message_callback(
source: u32,
gltype: u32,
id: u32,
severity: u32,
length: i32,
message: *const native_gl::GLchar,
user_param: *mut std::ffi::c_void,
) {
let _result = std::panic::catch_unwind(move || unsafe {
let callback: &mut DebugCallback = &mut *(user_param as *mut DebugCallback);
let slice = std::slice::from_raw_parts(message as *const u8, length as usize);
let msg = std::str::from_utf8(slice).unwrap();
(callback)(source, gltype, id, severity, msg);
});
}