diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/gleam | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/gleam/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/gleam/COPYING | 5 | ||||
-rw-r--r-- | third_party/rust/gleam/Cargo.toml | 24 | ||||
-rw-r--r-- | third_party/rust/gleam/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/gleam/LICENSE-MIT | 25 | ||||
-rw-r--r-- | third_party/rust/gleam/README.md | 6 | ||||
-rw-r--r-- | third_party/rust/gleam/build.rs | 88 | ||||
-rw-r--r-- | third_party/rust/gleam/rustfmt.toml | 0 | ||||
-rw-r--r-- | third_party/rust/gleam/src/gl.rs | 841 | ||||
-rw-r--r-- | third_party/rust/gleam/src/gl_fns.rs | 2293 | ||||
-rw-r--r-- | third_party/rust/gleam/src/gles_fns.rs | 2301 | ||||
-rw-r--r-- | third_party/rust/gleam/src/lib.rs | 25 |
12 files changed, 5810 insertions, 0 deletions
diff --git a/third_party/rust/gleam/.cargo-checksum.json b/third_party/rust/gleam/.cargo-checksum.json new file mode 100644 index 0000000000..651bf11aab --- /dev/null +++ b/third_party/rust/gleam/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"6dce42dfad850b93a2d4a2d29ab4c8de9c7bd783e6870ceec5fd8dccb960e50f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"1acb12040be43a3582d5897f11870b3ffdcd7ce0f4f32de158175bb6b33ec0b7","build.rs":"cf4ed31d33c2dcc3cb16648ce60c6ac69a7959fbd2491aa3565237f601a1ef18","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/gl.rs":"c10739f5382209a4a4715a9e38b3a263f750f52a7b5131c31683f0fd221e8d00","src/gl_fns.rs":"03c0232de8e1ffb8db3b4669cefe00f8e8c4ba49504276b0b84c88804cc01d13","src/gles_fns.rs":"7101fd4dbc354c2b375a8a525623d29ee5ac0e6cd13bf78c93a264fc50c0b589","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"0173481f2bb6e809bf4985de2e86c83876d84d2805830e3301cd37355e897f0f"}
\ No newline at end of file diff --git a/third_party/rust/gleam/COPYING b/third_party/rust/gleam/COPYING new file mode 100644 index 0000000000..8b7291ad28 --- /dev/null +++ b/third_party/rust/gleam/COPYING @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +option. All files in the project carrying such notice may not be +copied, modified, or distributed except according to those terms. diff --git a/third_party/rust/gleam/Cargo.toml b/third_party/rust/gleam/Cargo.toml new file mode 100644 index 0000000000..7cc789b302 --- /dev/null +++ b/third_party/rust/gleam/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "gleam" +version = "0.15.0" +authors = ["The Servo Project Developers"] +build = "build.rs" +description = "Generated OpenGL bindings and wrapper for Servo." +documentation = "https://doc.servo.org/gleam/" +readme = "README.md" +license = "Apache-2.0/MIT" +repository = "https://github.com/servo/gleam" + +[build-dependencies.gl_generator] +version = "0.14" diff --git a/third_party/rust/gleam/LICENSE-APACHE b/third_party/rust/gleam/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/gleam/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/gleam/LICENSE-MIT b/third_party/rust/gleam/LICENSE-MIT new file mode 100644 index 0000000000..807526f57f --- /dev/null +++ b/third_party/rust/gleam/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2012-2013 Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/gleam/README.md b/third_party/rust/gleam/README.md new file mode 100644 index 0000000000..1eaa2128fd --- /dev/null +++ b/third_party/rust/gleam/README.md @@ -0,0 +1,6 @@ +servo-gl +======== + +[Documentation](https://doc.servo.org/gleam/) + +OpenGL bindings for Servo diff --git a/third_party/rust/gleam/build.rs b/third_party/rust/gleam/build.rs new file mode 100644 index 0000000000..12fd38e373 --- /dev/null +++ b/third_party/rust/gleam/build.rs @@ -0,0 +1,88 @@ +extern crate gl_generator; + +use gl_generator::{Api, Fallbacks, Profile, Registry}; +use std::env; +use std::fs::File; +use std::path::Path; + +fn main() { + let dest = env::var("OUT_DIR").unwrap(); + let mut file_gl_and_gles = + File::create(&Path::new(&dest).join("gl_and_gles_bindings.rs")).unwrap(); + let mut file_gl = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap(); + let mut file_gles = File::create(&Path::new(&dest).join("gles_bindings.rs")).unwrap(); + + // OpenGL 3.3 bindings + let gl_extensions = [ + "GL_APPLE_client_storage", + "GL_APPLE_fence", + "GL_APPLE_texture_range", + "GL_APPLE_vertex_array_object", + "GL_ARB_blend_func_extended", + "GL_ARB_buffer_storage", + "GL_ARB_copy_image", + "GL_ARB_get_program_binary", + "GL_ARB_invalidate_subdata", + "GL_ARB_texture_rectangle", + "GL_ARB_texture_storage", + "GL_ARB_vertex_attrib_binding", + "GL_EXT_debug_marker", + "GL_EXT_texture_filter_anisotropic", + "GL_KHR_debug", + "GL_KHR_blend_equation_advanced", + "GL_KHR_blend_equation_advanced_coherent", + "GL_KHR_blend_equation_advanced_coherent", + "GL_ARB_shader_storage_buffer_object", + ]; + let gl_reg = Registry::new( + Api::Gl, + (3, 3), + Profile::Compatibility, + Fallbacks::All, + gl_extensions, + ); + gl_reg + .write_bindings(gl_generator::StructGenerator, &mut file_gl) + .unwrap(); + + // GLES 3.0 bindings + let gles_extensions = [ + "GL_EXT_buffer_storage", + "GL_EXT_copy_image", + "GL_EXT_debug_marker", + "GL_EXT_disjoint_timer_query", + "GL_EXT_shader_texture_lod", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_format_BGRA8888", + "GL_EXT_texture_storage", + "GL_OES_EGL_image_external", + "GL_OES_EGL_image", + "GL_OES_texture_half_float", + "GL_EXT_shader_pixel_local_storage", + "GL_ANGLE_provoking_vertex", + "GL_ANGLE_texture_usage", + "GL_CHROMIUM_copy_texture", + "GL_KHR_debug", + "GL_KHR_blend_equation_advanced", + "GL_KHR_blend_equation_advanced_coherent", + "GL_ANGLE_copy_texture_3d", + "GL_QCOM_tiled_rendering", + ]; + let gles_reg = Registry::new( + Api::Gles2, + // using 3.1 to get SSBO support + (3, 1), + Profile::Core, + Fallbacks::All, + gles_extensions, + ); + gles_reg + .write_bindings(gl_generator::StructGenerator, &mut file_gles) + .unwrap(); + + // OpenGL 3.3 + GLES 3.0 bindings. Used to get all enums + let gl_reg = gl_reg + gles_reg; + gl_reg + .write_bindings(gl_generator::StructGenerator, &mut file_gl_and_gles) + .unwrap(); +} diff --git a/third_party/rust/gleam/rustfmt.toml b/third_party/rust/gleam/rustfmt.toml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/rust/gleam/rustfmt.toml diff --git a/third_party/rust/gleam/src/gl.rs b/third_party/rust/gleam/src/gl.rs new file mode 100644 index 0000000000..6293d81100 --- /dev/null +++ b/third_party/rust/gleam/src/gl.rs @@ -0,0 +1,841 @@ +// Copyright 2014 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi; +use std::ffi::{CStr, CString}; +use std::mem; +use std::mem::size_of; +use std::os::raw::{c_char, c_int, c_void}; +use std::ptr; +use std::rc::Rc; +use std::str; +use std::time::{Duration, Instant}; + +pub use ffi::types::*; +pub use ffi::*; + +pub use ffi_gl::Gl as GlFfi; +pub use ffi_gles::Gles2 as GlesFfi; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum GlType { + Gl, + Gles, +} + +impl Default for GlType { + #[cfg(any(target_os = "android", target_os = "ios"))] + fn default() -> GlType { + GlType::Gles + } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + fn default() -> GlType { + GlType::Gl + } +} + +fn bpp(format: GLenum, pixel_type: GLenum) -> GLsizei { + let colors = match format { + ffi::RED => 1, + ffi::RGB => 3, + ffi::BGR => 3, + + ffi::RGBA => 4, + ffi::BGRA => 4, + + ffi::ALPHA => 1, + ffi::R16 => 1, + ffi::LUMINANCE => 1, + ffi::DEPTH_COMPONENT => 1, + _ => panic!("unsupported format for read_pixels: {:?}", format), + }; + let depth = match pixel_type { + ffi::UNSIGNED_BYTE => 1, + ffi::UNSIGNED_SHORT => 2, + ffi::SHORT => 2, + ffi::FLOAT => 4, + ffi::UNSIGNED_INT_8_8_8_8_REV => return 4, + _ => panic!("unsupported pixel_type for read_pixels: {:?}", pixel_type), + }; + colors * depth +} + +fn calculate_length(width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> usize { + (width * height * bpp(format, pixel_type)) as usize +} + +pub struct DebugMessage { + pub message: String, + pub source: GLenum, + pub ty: GLenum, + pub id: GLenum, + pub severity: GLenum, +} + +macro_rules! declare_gl_apis { + // garbo is a hack to handle unsafe methods. + ($($(unsafe $([$garbo:expr])*)* fn $name:ident(&self $(, $arg:ident: $t:ty)* $(,)*) $(-> $retty:ty)* ;)+) => { + pub trait Gl { + $($(unsafe $($garbo)*)* fn $name(&self $(, $arg:$t)*) $(-> $retty)* ;)+ + } + + impl Gl for ErrorCheckingGl { + $($(unsafe $($garbo)*)* fn $name(&self $(, $arg:$t)*) $(-> $retty)* { + let rv = self.gl.$name($($arg,)*); + assert_eq!(self.gl.get_error(), 0); + rv + })+ + } + + impl<F: Fn(&dyn Gl, &str, GLenum)> Gl for ErrorReactingGl<F> { + $($(unsafe $($garbo)*)* fn $name(&self $(, $arg:$t)*) $(-> $retty)* { + let rv = self.gl.$name($($arg,)*); + let error = self.gl.get_error(); + if error != 0 { + (self.callback)(&*self.gl, stringify!($name), error); + } + rv + })+ + } + + impl<F: Fn(&str, Duration)> Gl for ProfilingGl<F> { + $($(unsafe $($garbo)*)* fn $name(&self $(, $arg:$t)*) $(-> $retty)* { + let start = Instant::now(); + let rv = self.gl.$name($($arg,)*); + let duration = Instant::now() - start; + if duration > self.threshold { + (self.callback)(stringify!($name), duration); + } + rv + })+ + } + } +} + +declare_gl_apis! { + fn get_type(&self) -> GlType; + fn buffer_data_untyped( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + usage: GLenum, + ); + fn buffer_sub_data_untyped( + &self, + target: GLenum, + offset: isize, + size: GLsizeiptr, + data: *const GLvoid, + ); + fn map_buffer(&self, target: GLenum, access: GLbitfield) -> *mut c_void; + fn map_buffer_range( + &self, + target: GLenum, + offset: GLintptr, + length: GLsizeiptr, + access: GLbitfield, + ) -> *mut c_void; + fn unmap_buffer(&self, target: GLenum) -> GLboolean; + fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint); + fn shader_source(&self, shader: GLuint, strings: &[&[u8]]); + fn read_buffer(&self, mode: GLenum); + fn read_pixels_into_buffer( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + dst_buffer: &mut [u8], + ); + fn read_pixels( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + ) -> Vec<u8>; + unsafe fn read_pixels_into_pbo( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + ); + fn sample_coverage(&self, value: GLclampf, invert: bool); + fn polygon_offset(&self, factor: GLfloat, units: GLfloat); + fn pixel_store_i(&self, name: GLenum, param: GLint); + fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_textures(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_vertex_arrays_apple(&self, n: GLsizei) -> Vec<GLuint>; + fn gen_queries(&self, n: GLsizei) -> Vec<GLuint>; + fn begin_query(&self, target: GLenum, id: GLuint); + fn end_query(&self, target: GLenum); + fn query_counter(&self, id: GLuint, target: GLenum); + fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32; + fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32; + fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64; + fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64; + fn delete_queries(&self, queries: &[GLuint]); + fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]); + fn delete_vertex_arrays_apple(&self, vertex_arrays: &[GLuint]); + fn delete_buffers(&self, buffers: &[GLuint]); + fn delete_renderbuffers(&self, renderbuffers: &[GLuint]); + fn delete_framebuffers(&self, framebuffers: &[GLuint]); + fn delete_textures(&self, textures: &[GLuint]); + fn framebuffer_renderbuffer( + &self, + target: GLenum, + attachment: GLenum, + renderbuffertarget: GLenum, + renderbuffer: GLuint, + ); + fn renderbuffer_storage( + &self, + target: GLenum, + internalformat: GLenum, + width: GLsizei, + height: GLsizei, + ); + fn depth_func(&self, func: GLenum); + fn active_texture(&self, texture: GLenum); + fn attach_shader(&self, program: GLuint, shader: GLuint); + fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str); + unsafe fn get_uniform_iv(&self, program: GLuint, location: GLint, result: &mut [GLint]); + unsafe fn get_uniform_fv(&self, program: GLuint, location: GLint, result: &mut [GLfloat]); + fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint; + fn get_uniform_indices(&self, program: GLuint, names: &[&str]) -> Vec<GLuint>; + fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint); + fn bind_buffer_range( + &self, + target: GLenum, + index: GLuint, + buffer: GLuint, + offset: GLintptr, + size: GLsizeiptr, + ); + fn uniform_block_binding( + &self, + program: GLuint, + uniform_block_index: GLuint, + uniform_block_binding: GLuint, + ); + fn bind_buffer(&self, target: GLenum, buffer: GLuint); + fn bind_vertex_array(&self, vao: GLuint); + fn bind_vertex_array_apple(&self, vao: GLuint); + fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint); + fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint); + fn bind_texture(&self, target: GLenum, texture: GLuint); + fn bind_vertex_buffer(&self, binding_index: GLuint, buffer: GLuint, offset: GLintptr, stride: GLint); + fn draw_buffers(&self, bufs: &[GLenum]); + fn tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ); + fn compressed_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + border: GLint, + data: &[u8], + ); + fn compressed_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + data: &[u8], + ); + fn tex_image_3d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ); + fn copy_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + ); + fn copy_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ); + fn copy_tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ); + fn tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ); + fn tex_sub_image_2d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ); + fn tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ); + fn tex_sub_image_3d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ); + fn tex_storage_2d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + ); + fn tex_storage_3d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + ); + fn get_tex_image_into_buffer( + &self, + target: GLenum, + level: GLint, + format: GLenum, + ty: GLenum, + output: &mut [u8], + ); + unsafe fn copy_image_sub_data( + &self, + src_name: GLuint, + src_target: GLenum, + src_level: GLint, + src_x: GLint, + src_y: GLint, + src_z: GLint, + dst_name: GLuint, + dst_target: GLenum, + dst_level: GLint, + dst_x: GLint, + dst_y: GLint, + dst_z: GLint, + src_width: GLsizei, + src_height: GLsizei, + src_depth: GLsizei, + ); + + fn invalidate_framebuffer(&self, target: GLenum, attachments: &[GLenum]); + fn invalidate_sub_framebuffer( + &self, + target: GLenum, + attachments: &[GLenum], + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + ); + + unsafe fn get_integer_v(&self, name: GLenum, result: &mut [GLint]); + unsafe fn get_integer_64v(&self, name: GLenum, result: &mut [GLint64]); + unsafe fn get_integer_iv(&self, name: GLenum, index: GLuint, result: &mut [GLint]); + unsafe fn get_integer_64iv(&self, name: GLenum, index: GLuint, result: &mut [GLint64]); + unsafe fn get_boolean_v(&self, name: GLenum, result: &mut [GLboolean]); + unsafe fn get_float_v(&self, name: GLenum, result: &mut [GLfloat]); + + fn get_framebuffer_attachment_parameter_iv( + &self, + target: GLenum, + attachment: GLenum, + pname: GLenum, + ) -> GLint; + fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint; + fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint; + fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat; + fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint); + fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat); + fn framebuffer_texture_2d( + &self, + target: GLenum, + attachment: GLenum, + textarget: GLenum, + texture: GLuint, + level: GLint, + ); + fn framebuffer_texture_layer( + &self, + target: GLenum, + attachment: GLenum, + texture: GLuint, + level: GLint, + layer: GLint, + ); + fn blit_framebuffer( + &self, + src_x0: GLint, + src_y0: GLint, + src_x1: GLint, + src_y1: GLint, + dst_x0: GLint, + dst_y0: GLint, + dst_x1: GLint, + dst_y1: GLint, + mask: GLbitfield, + filter: GLenum, + ); + fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat); + fn vertex_attrib_binding(&self, attrib_index: GLuint, binding_index: GLuint); + fn vertex_attrib_pointer_f32( + &self, + index: GLuint, + size: GLint, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ); + fn vertex_attrib_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ); + fn vertex_attrib_i_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + stride: GLsizei, + offset: GLuint, + ); + fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint); + fn vertex_attrib_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, normalized: bool, relative_offset: GLuint); + fn vertex_attrib_i_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, relative_offset: GLuint); + fn vertex_binding_divisor(&self, binding_index: GLuint, divisor: GLuint); + fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei); + fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei); + fn line_width(&self, width: GLfloat); + fn use_program(&self, program: GLuint); + fn validate_program(&self, program: GLuint); + fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei); + fn draw_arrays_instanced(&self, mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei); + fn draw_elements( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + ); + fn draw_elements_instanced( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + primcount: GLsizei, + ); + fn blend_color(&self, r: f32, g: f32, b: f32, a: f32); + fn blend_func(&self, sfactor: GLenum, dfactor: GLenum); + fn blend_func_separate( + &self, + src_rgb: GLenum, + dest_rgb: GLenum, + src_alpha: GLenum, + dest_alpha: GLenum, + ); + fn blend_equation(&self, mode: GLenum); + fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum); + fn color_mask(&self, r: bool, g: bool, b: bool, a: bool); + fn cull_face(&self, mode: GLenum); + fn front_face(&self, mode: GLenum); + fn enable(&self, cap: GLenum); + fn disable(&self, cap: GLenum); + fn hint(&self, param_name: GLenum, param_val: GLenum); + fn is_enabled(&self, cap: GLenum) -> GLboolean; + fn is_shader(&self, shader: GLuint) -> GLboolean; + fn is_texture(&self, texture: GLenum) -> GLboolean; + fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean; + fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean; + fn check_frame_buffer_status(&self, target: GLenum) -> GLenum; + fn enable_vertex_attrib_array(&self, index: GLuint); + fn disable_vertex_attrib_array(&self, index: GLuint); + fn uniform_1f(&self, location: GLint, v0: GLfloat); + fn uniform_1fv(&self, location: GLint, values: &[f32]); + fn uniform_1i(&self, location: GLint, v0: GLint); + fn uniform_1iv(&self, location: GLint, values: &[i32]); + fn uniform_1ui(&self, location: GLint, v0: GLuint); + fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat); + fn uniform_2fv(&self, location: GLint, values: &[f32]); + fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint); + fn uniform_2iv(&self, location: GLint, values: &[i32]); + fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint); + fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat); + fn uniform_3fv(&self, location: GLint, values: &[f32]); + fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint); + fn uniform_3iv(&self, location: GLint, values: &[i32]); + fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint); + fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat); + fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint); + fn uniform_4iv(&self, location: GLint, values: &[i32]); + fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint); + fn uniform_4fv(&self, location: GLint, values: &[f32]); + fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]); + fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]); + fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]); + fn depth_mask(&self, flag: bool); + fn depth_range(&self, near: f64, far: f64); + fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String); + fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String); + fn get_active_uniforms_iv( + &self, + program: GLuint, + indices: Vec<GLuint>, + pname: GLenum, + ) -> Vec<GLint>; + fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint; + fn get_active_uniform_block_iv( + &self, + program: GLuint, + index: GLuint, + pname: GLenum, + ) -> Vec<GLint>; + fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> String; + fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int; + fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int; + fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int; + fn get_program_info_log(&self, program: GLuint) -> String; + unsafe fn get_program_iv(&self, program: GLuint, pname: GLenum, result: &mut [GLint]); + fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum); + fn program_binary(&self, program: GLuint, format: GLenum, binary: &[u8]); + fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint); + unsafe fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, result: &mut [GLint]); + unsafe fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, result: &mut [GLfloat]); + fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr; + fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint; + fn get_shader_info_log(&self, shader: GLuint) -> String; + fn get_string(&self, which: GLenum) -> String; + fn get_string_i(&self, which: GLenum, index: GLuint) -> String; + unsafe fn get_shader_iv(&self, shader: GLuint, pname: GLenum, result: &mut [GLint]); + fn get_shader_precision_format( + &self, + shader_type: GLuint, + precision_type: GLuint, + ) -> (GLint, GLint, GLint); + fn compile_shader(&self, shader: GLuint); + fn create_program(&self) -> GLuint; + fn delete_program(&self, program: GLuint); + fn create_shader(&self, shader_type: GLenum) -> GLuint; + fn delete_shader(&self, shader: GLuint); + fn detach_shader(&self, program: GLuint, shader: GLuint); + fn link_program(&self, program: GLuint); + fn clear_color(&self, r: f32, g: f32, b: f32, a: f32); + fn clear(&self, buffer_mask: GLbitfield); + fn clear_depth(&self, depth: f64); + fn clear_stencil(&self, s: GLint); + fn flush(&self); + fn finish(&self); + fn get_error(&self) -> GLenum; + fn stencil_mask(&self, mask: GLuint); + fn stencil_mask_separate(&self, face: GLenum, mask: GLuint); + fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint); + fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint); + fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum); + fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum); + fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES); + fn egl_image_target_renderbuffer_storage_oes(&self, target: GLenum, image: GLeglImageOES); + fn generate_mipmap(&self, target: GLenum); + fn insert_event_marker_ext(&self, message: &str); + fn push_group_marker_ext(&self, message: &str); + fn pop_group_marker_ext(&self); + fn debug_message_insert_khr( + &self, + source: GLenum, + type_: GLenum, + id: GLuint, + severity: GLenum, + message: &str, + ); + fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str); + fn pop_debug_group_khr(&self); + fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsync; + fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum; + fn wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64); + fn delete_sync(&self, sync: GLsync); + fn texture_range_apple(&self, target: GLenum, data: &[u8]); + fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint>; + fn delete_fences_apple(&self, fences: &[GLuint]); + fn set_fence_apple(&self, fence: GLuint); + fn finish_fence_apple(&self, fence: GLuint); + fn test_fence_apple(&self, fence: GLuint); + fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean; + fn finish_object_apple(&self, object: GLenum, name: GLuint); + // GL_KHR_blend_equation_advanced + fn blend_barrier_khr(&self); + + // GL_ARB_blend_func_extended + fn bind_frag_data_location_indexed( + &self, + program: GLuint, + color_number: GLuint, + index: GLuint, + name: &str, + ); + fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint; + + // GL_KHR_debug + fn get_debug_messages(&self) -> Vec<DebugMessage>; + + // GL_ANGLE_provoking_vertex + fn provoking_vertex_angle(&self, mode: GLenum); + + // GL_CHROMIUM_copy_texture + fn copy_texture_chromium( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + internal_format: GLint, + dest_type: GLenum, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ); + fn copy_sub_texture_chromium( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + x_offset: GLint, + y_offset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ); + + // GL_ANGLE_copy_texture_3d + fn copy_texture_3d_angle( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + internal_format: GLint, + dest_type: GLenum, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ); + + fn copy_sub_texture_3d_angle( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + x_offset: GLint, + y_offset: GLint, + z_offset: GLint, + x: GLint, + y: GLint, + z: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ); + + fn buffer_storage( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + flags: GLbitfield, + ); + + fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr); + + fn start_tiling_qcom(&self, x: GLuint, y: GLuint, width: GLuint, height: GLuint, preserve_mask: GLbitfield); + fn end_tiling_qcom(&self, preserve_mask: GLbitfield); +} + +//#[deprecated(since = "0.6.11", note = "use ErrorReactingGl instead")] +pub struct ErrorCheckingGl { + gl: Rc<dyn Gl>, +} + +impl ErrorCheckingGl { + pub fn wrap(fns: Rc<dyn Gl>) -> Rc<dyn Gl> { + Rc::new(ErrorCheckingGl { gl: fns }) as Rc<dyn Gl> + } +} + +/// A wrapper around GL context that calls a specified callback on each GL error. +pub struct ErrorReactingGl<F> { + gl: Rc<dyn Gl>, + callback: F, +} + +impl<F: 'static + Fn(&dyn Gl, &str, GLenum)> ErrorReactingGl<F> { + pub fn wrap(fns: Rc<dyn Gl>, callback: F) -> Rc<dyn Gl> { + Rc::new(ErrorReactingGl { gl: fns, callback }) as Rc<dyn Gl> + } +} + +/// A wrapper around GL context that times each call and invokes the callback +/// if the call takes longer than the threshold. +pub struct ProfilingGl<F> { + gl: Rc<dyn Gl>, + threshold: Duration, + callback: F, +} + +impl<F: 'static + Fn(&str, Duration)> ProfilingGl<F> { + pub fn wrap(fns: Rc<dyn Gl>, threshold: Duration, callback: F) -> Rc<dyn Gl> { + Rc::new(ProfilingGl { + gl: fns, + threshold, + callback, + }) as Rc<dyn Gl> + } +} + +#[inline] +pub fn buffer_data<T>(gl_: &dyn Gl, target: GLenum, data: &[T], usage: GLenum) { + gl_.buffer_data_untyped( + target, + (data.len() * size_of::<T>()) as GLsizeiptr, + data.as_ptr() as *const GLvoid, + usage, + ) +} + +#[inline] +pub fn buffer_data_raw<T>(gl_: &dyn Gl, target: GLenum, data: &T, usage: GLenum) { + gl_.buffer_data_untyped( + target, + size_of::<T>() as GLsizeiptr, + data as *const T as *const GLvoid, + usage, + ) +} + +#[inline] +pub fn buffer_sub_data<T>(gl_: &dyn Gl, target: GLenum, offset: isize, data: &[T]) { + gl_.buffer_sub_data_untyped( + target, + offset, + (data.len() * size_of::<T>()) as GLsizeiptr, + data.as_ptr() as *const GLvoid, + ); +} + +include!("gl_fns.rs"); +include!("gles_fns.rs"); diff --git a/third_party/rust/gleam/src/gl_fns.rs b/third_party/rust/gleam/src/gl_fns.rs new file mode 100644 index 0000000000..8e00c7e563 --- /dev/null +++ b/third_party/rust/gleam/src/gl_fns.rs @@ -0,0 +1,2293 @@ +// Copyright 2014 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct GlFns { + ffi_gl_: GlFfi, +} + +impl GlFns { + pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<dyn Gl> + where + F: FnMut(&str) -> *const c_void, + { + let ffi_gl_ = GlFfi::load_with(loadfn); + Rc::new(GlFns { ffi_gl_: ffi_gl_ }) as Rc<dyn Gl> + } +} + +impl Gl for GlFns { + fn get_type(&self) -> GlType { + GlType::Gl + } + + fn buffer_data_untyped( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + usage: GLenum, + ) { + unsafe { + self.ffi_gl_.BufferData(target, size, data, usage); + } + } + + fn buffer_sub_data_untyped( + &self, + target: GLenum, + offset: isize, + size: GLsizeiptr, + data: *const GLvoid, + ) { + unsafe { + self.ffi_gl_.BufferSubData(target, offset, size, data); + } + } + + fn map_buffer(&self, + target: GLenum, + access: GLbitfield) -> *mut c_void { + unsafe { + return self.ffi_gl_.MapBuffer(target, access); + } + } + + fn map_buffer_range(&self, + target: GLenum, + offset: GLintptr, + length: GLsizeiptr, + access: GLbitfield) -> *mut c_void { + unsafe { + return self.ffi_gl_.MapBufferRange(target, offset, length, access); + } + } + + fn unmap_buffer(&self, target: GLenum) -> GLboolean { + unsafe { + return self.ffi_gl_.UnmapBuffer(target); + } + } + + fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) { + let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect(); + let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect(); + unsafe { + self.ffi_gl_.ShaderSource( + shader, + pointers.len() as GLsizei, + pointers.as_ptr() as *const *const GLchar, + lengths.as_ptr(), + ); + } + drop(lengths); + drop(pointers); + } + + fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) { + unsafe { + self.ffi_gl_.TexBuffer(target, internal_format, buffer); + } + } + + fn read_buffer(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.ReadBuffer(mode); + } + } + + fn read_pixels_into_buffer( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + dst_buffer: &mut [u8], + ) { + // Assumes that the user properly allocated the size for dst_buffer. + let mut row_length = 0; + unsafe { + self.ffi_gl_.GetIntegerv(ffi::PACK_ROW_LENGTH, &mut row_length as _); + } + if row_length == 0 { + row_length = width; + } else { + assert!(row_length >= width); + } + assert_eq!(calculate_length(row_length, height, format, pixel_type), dst_buffer.len()); + + unsafe { + // We don't want any alignment padding on pixel rows. + self.ffi_gl_.PixelStorei(ffi::PACK_ALIGNMENT, 1); + self.ffi_gl_.ReadPixels( + x, + y, + width, + height, + format, + pixel_type, + dst_buffer.as_mut_ptr() as *mut c_void, + ); + } + } + + fn read_pixels( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + ) -> Vec<u8> { + let len = calculate_length(width, height, format, pixel_type); + let mut pixels: Vec<u8> = Vec::new(); + pixels.reserve(len); + unsafe { + pixels.set_len(len); + } + + self.read_pixels_into_buffer( + x, + y, + width, + height, + format, + pixel_type, + pixels.as_mut_slice(), + ); + + pixels + } + + unsafe fn read_pixels_into_pbo(&self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum) { + self.ffi_gl_.ReadPixels(x, y, width, height, format, pixel_type, ptr::null_mut()); + } + + fn sample_coverage(&self, value: GLclampf, invert: bool) { + unsafe { + self.ffi_gl_.SampleCoverage(value, invert as GLboolean); + } + } + + fn polygon_offset(&self, factor: GLfloat, units: GLfloat) { + unsafe { + self.ffi_gl_.PolygonOffset(factor, units); + } + } + + fn pixel_store_i(&self, name: GLenum, param: GLint) { + unsafe { + self.ffi_gl_.PixelStorei(name, param); + } + } + + fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenBuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenTextures(n, result.as_mut_ptr()); + } + result + } + + fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr()) + } + result + } + + fn gen_vertex_arrays_apple(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenVertexArraysAPPLE(n, result.as_mut_ptr()) + } + result + } + + fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenQueries(n, result.as_mut_ptr()); + } + result + } + + fn begin_query(&self, target: GLenum, id: GLuint) { + unsafe { + self.ffi_gl_.BeginQuery(target, id); + } + } + + fn end_query(&self, target: GLenum) { + unsafe { + self.ffi_gl_.EndQuery(target); + } + } + + fn query_counter(&self, id: GLuint, target: GLenum) { + unsafe { + self.ffi_gl_.QueryCounter(id, target); + } + } + + fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 { + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectiv(id, pname, &mut result); + } + result + } + + fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 { + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectuiv(id, pname, &mut result); + } + result + } + + fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 { + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjecti64v(id, pname, &mut result); + } + result + } + + fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 { + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectui64v(id, pname, &mut result); + } + result + } + + fn delete_queries(&self, queries: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteQueries(queries.len() as GLsizei, queries.as_ptr()); + } + } + + fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr()); + } + } + + fn delete_vertex_arrays_apple(&self, vertex_arrays: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteVertexArraysAPPLE(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr()); + } + } + + fn delete_buffers(&self, buffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr()); + } + } + + fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr()); + } + } + + fn delete_framebuffers(&self, framebuffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr()); + } + } + + fn delete_textures(&self, textures: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteTextures(textures.len() as GLsizei, textures.as_ptr()); + } + } + + fn framebuffer_renderbuffer( + &self, + target: GLenum, + attachment: GLenum, + renderbuffertarget: GLenum, + renderbuffer: GLuint, + ) { + unsafe { + self.ffi_gl_.FramebufferRenderbuffer( + target, + attachment, + renderbuffertarget, + renderbuffer, + ); + } + } + + fn renderbuffer_storage( + &self, + target: GLenum, + internalformat: GLenum, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .RenderbufferStorage(target, internalformat, width, height); + } + } + + fn depth_func(&self, func: GLenum) { + unsafe { + self.ffi_gl_.DepthFunc(func); + } + } + + fn active_texture(&self, texture: GLenum) { + unsafe { + self.ffi_gl_.ActiveTexture(texture); + } + } + + fn attach_shader(&self, program: GLuint, shader: GLuint) { + unsafe { + self.ffi_gl_.AttachShader(program, shader); + } + } + + fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) { + let c_string = CString::new(name).unwrap(); + unsafe { + self.ffi_gl_ + .BindAttribLocation(program, index, c_string.as_ptr()) + } + } + + // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml + unsafe fn get_uniform_iv(&self, program: GLuint, location: GLint, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetUniformiv(program, location, result.as_mut_ptr()); + } + + // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml + unsafe fn get_uniform_fv(&self, program: GLuint, location: GLint, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetUniformfv(program, location, result.as_mut_ptr()); + } + + fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint { + let c_string = CString::new(name).unwrap(); + unsafe { + self.ffi_gl_ + .GetUniformBlockIndex(program, c_string.as_ptr()) + } + } + + fn get_uniform_indices(&self, program: GLuint, names: &[&str]) -> Vec<GLuint> { + let c_strings: Vec<CString> = names.iter().map(|n| CString::new(*n).unwrap()).collect(); + let pointers: Vec<*const GLchar> = c_strings.iter().map(|string| string.as_ptr()).collect(); + let mut result = Vec::with_capacity(c_strings.len()); + unsafe { + result.set_len(c_strings.len()); + self.ffi_gl_.GetUniformIndices( + program, + pointers.len() as GLsizei, + pointers.as_ptr(), + result.as_mut_ptr(), + ); + } + result + } + + fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) { + unsafe { + self.ffi_gl_.BindBufferBase(target, index, buffer); + } + } + + fn bind_buffer_range( + &self, + target: GLenum, + index: GLuint, + buffer: GLuint, + offset: GLintptr, + size: GLsizeiptr, + ) { + unsafe { + self.ffi_gl_ + .BindBufferRange(target, index, buffer, offset, size); + } + } + + fn uniform_block_binding( + &self, + program: GLuint, + uniform_block_index: GLuint, + uniform_block_binding: GLuint, + ) { + unsafe { + self.ffi_gl_ + .UniformBlockBinding(program, uniform_block_index, uniform_block_binding); + } + } + + fn bind_buffer(&self, target: GLenum, buffer: GLuint) { + unsafe { + self.ffi_gl_.BindBuffer(target, buffer); + } + } + + fn bind_vertex_array(&self, vao: GLuint) { + unsafe { + self.ffi_gl_.BindVertexArray(vao); + } + } + + fn bind_vertex_array_apple(&self, vao: GLuint) { + unsafe { + self.ffi_gl_.BindVertexArrayAPPLE(vao) + } + } + + fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) { + unsafe { + self.ffi_gl_.BindRenderbuffer(target, renderbuffer); + } + } + + fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) { + unsafe { + self.ffi_gl_.BindFramebuffer(target, framebuffer); + } + } + + fn bind_texture(&self, target: GLenum, texture: GLuint) { + unsafe { + self.ffi_gl_.BindTexture(target, texture); + } + } + + fn bind_vertex_buffer(&self, binding_index: GLuint, buffer: GLuint, offset: GLintptr, stride: GLint) { + unsafe { self.ffi_gl_.BindVertexBuffer(binding_index, buffer, offset, stride) } + } + + fn draw_buffers(&self, bufs: &[GLenum]) { + unsafe { + self.ffi_gl_ + .DrawBuffers(bufs.len() as GLsizei, bufs.as_ptr()); + } + } + + // FIXME: Does not verify buffer size -- unsafe! + fn tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ) { + match opt_data { + Some(data) => unsafe { + self.ffi_gl_.TexImage2D( + target, + level, + internal_format, + width, + height, + border, + format, + ty, + data.as_ptr() as *const GLvoid, + ); + }, + None => unsafe { + self.ffi_gl_.TexImage2D( + target, + level, + internal_format, + width, + height, + border, + format, + ty, + ptr::null(), + ); + }, + } + } + + fn compressed_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + border: GLint, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.CompressedTexImage2D( + target, + level, + internal_format, + width, + height, + border, + data.len() as GLsizei, + data.as_ptr() as *const GLvoid, + ); + } + } + + fn compressed_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.CompressedTexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + data.len() as GLsizei, + data.as_ptr() as *const GLvoid, + ); + } + } + + // FIXME: Does not verify buffer size -- unsafe! + fn tex_image_3d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ) { + unsafe { + let pdata = match opt_data { + Some(data) => mem::transmute(data.as_ptr()), + None => ptr::null(), + }; + self.ffi_gl_.TexImage3D( + target, + level, + internal_format, + width, + height, + depth, + border, + format, + ty, + pdata, + ); + } + } + + fn copy_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + ) { + unsafe { + self.ffi_gl_.CopyTexImage2D( + target, + level, + internal_format, + x, + y, + width, + height, + border, + ); + } + } + + fn copy_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + } + } + + fn copy_tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_.CopyTexSubImage3D( + target, level, xoffset, yoffset, zoffset, x, y, width, height, + ); + } + } + + fn tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.TexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + ty, + data.as_ptr() as *const c_void, + ); + } + } + + fn tex_sub_image_2d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ) { + unsafe { + self.ffi_gl_.TexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + ty, + offset as *const c_void, + ); + } + } + + fn tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.TexSubImage3D( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + ty, + data.as_ptr() as *const c_void, + ); + } + } + + fn tex_sub_image_3d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ) { + unsafe { + self.ffi_gl_.TexSubImage3D( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + ty, + offset as *const c_void, + ); + } + } + + fn tex_storage_2d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + ) { + if self.ffi_gl_.TexStorage2D.is_loaded() { + unsafe { + self.ffi_gl_ + .TexStorage2D(target, levels, internal_format, width, height); + } + } + } + + fn tex_storage_3d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + ) { + if self.ffi_gl_.TexStorage3D.is_loaded() { + unsafe { + self.ffi_gl_ + .TexStorage3D(target, levels, internal_format, width, height, depth); + } + } + } + + fn get_tex_image_into_buffer( + &self, + target: GLenum, + level: GLint, + format: GLenum, + ty: GLenum, + output: &mut [u8], + ) { + unsafe { + self.ffi_gl_ + .GetTexImage(target, level, format, ty, output.as_mut_ptr() as *mut _); + } + } + + unsafe fn copy_image_sub_data( + &self, + src_name: GLuint, + src_target: GLenum, + src_level: GLint, + src_x: GLint, + src_y: GLint, + src_z: GLint, + dst_name: GLuint, + dst_target: GLenum, + dst_level: GLint, + dst_x: GLint, + dst_y: GLint, + dst_z: GLint, + src_width: GLsizei, + src_height: GLsizei, + src_depth: GLsizei, + ) { + self.ffi_gl_.CopyImageSubData( + src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target, dst_level, + dst_x, dst_y, dst_z, src_width, src_height, src_depth, + ); + } + + fn invalidate_framebuffer(&self, target: GLenum, attachments: &[GLenum]) { + if self.ffi_gl_.InvalidateFramebuffer.is_loaded() { + unsafe { + self.ffi_gl_.InvalidateFramebuffer( + target, + attachments.len() as GLsizei, + attachments.as_ptr(), + ); + } + } + } + + fn invalidate_sub_framebuffer( + &self, + target: GLenum, + attachments: &[GLenum], + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + ) { + if self.ffi_gl_.InvalidateSubFramebuffer.is_loaded() { + unsafe { + self.ffi_gl_.InvalidateSubFramebuffer( + target, + attachments.len() as GLsizei, + attachments.as_ptr(), + xoffset, + yoffset, + width, + height, + ); + } + } + } + + #[inline] + unsafe fn get_integer_v(&self, name: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetIntegerv(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_64v(&self, name: GLenum, result: &mut [GLint64]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetInteger64v(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_iv(&self, name: GLenum, index: GLuint, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetIntegeri_v(name, index, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_64iv(&self, name: GLenum, index: GLuint, result: &mut [GLint64]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetInteger64i_v(name, index, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_boolean_v(&self, name: GLenum, result: &mut [GLboolean]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetBooleanv(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_float_v(&self, name: GLenum, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetFloatv(name, result.as_mut_ptr()); + } + + fn get_framebuffer_attachment_parameter_iv( + &self, + target: GLenum, + attachment: GLenum, + pname: GLenum, + ) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_.GetFramebufferAttachmentParameteriv( + target, + attachment, + pname, + &mut result, + ); + } + result + } + + fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_ + .GetRenderbufferParameteriv(target, pname, &mut result); + } + result + } + + fn get_tex_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_.GetTexParameteriv(target, pname, &mut result); + } + result + } + + fn get_tex_parameter_fv(&self, target: GLenum, pname: GLenum) -> GLfloat { + let mut result: GLfloat = 0.0; + unsafe { + self.ffi_gl_.GetTexParameterfv(target, pname, &mut result); + } + result + } + + fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) { + unsafe { + self.ffi_gl_.TexParameteri(target, pname, param); + } + } + + fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) { + unsafe { + self.ffi_gl_.TexParameterf(target, pname, param); + } + } + + fn framebuffer_texture_2d( + &self, + target: GLenum, + attachment: GLenum, + textarget: GLenum, + texture: GLuint, + level: GLint, + ) { + unsafe { + self.ffi_gl_ + .FramebufferTexture2D(target, attachment, textarget, texture, level); + } + } + + fn framebuffer_texture_layer( + &self, + target: GLenum, + attachment: GLenum, + texture: GLuint, + level: GLint, + layer: GLint, + ) { + unsafe { + self.ffi_gl_ + .FramebufferTextureLayer(target, attachment, texture, level, layer); + } + } + + fn blit_framebuffer( + &self, + src_x0: GLint, + src_y0: GLint, + src_x1: GLint, + src_y1: GLint, + dst_x0: GLint, + dst_y0: GLint, + dst_x1: GLint, + dst_y1: GLint, + mask: GLbitfield, + filter: GLenum, + ) { + unsafe { + self.ffi_gl_.BlitFramebuffer( + src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter, + ); + } + } + + fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) { + unsafe { self.ffi_gl_.VertexAttrib4f(index, x, y, z, w) } + } + + fn vertex_attrib_binding(&self, attrib_index: GLuint, binding_index: GLuint) { + unsafe { self.ffi_gl_.VertexAttribBinding(attrib_index, binding_index) } + } + + fn vertex_attrib_pointer_f32( + &self, + index: GLuint, + size: GLint, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_.VertexAttribPointer( + index, + size, + ffi::FLOAT, + normalized as GLboolean, + stride, + offset as *const GLvoid, + ) + } + } + + fn vertex_attrib_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_.VertexAttribPointer( + index, + size, + type_, + normalized as GLboolean, + stride, + offset as *const GLvoid, + ) + } + } + + fn vertex_attrib_i_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_ + .VertexAttribIPointer(index, size, type_, stride, offset as *const GLvoid) + } + } + + fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) { + unsafe { self.ffi_gl_.VertexAttribDivisor(index, divisor) } + } + + fn vertex_attrib_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, normalized: bool, relative_offset: GLuint) { + unsafe { self.ffi_gl_.VertexAttribFormat(attrib_index, size, type_, normalized as GLboolean, relative_offset) } + } + + fn vertex_attrib_i_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, relative_offset: GLuint) { + unsafe { self.ffi_gl_.VertexAttribIFormat(attrib_index, size, type_, relative_offset) } + } + + fn vertex_binding_divisor(&self, binding_index: GLuint, divisor: GLuint) { + unsafe { self.ffi_gl_.VertexBindingDivisor(binding_index, divisor) } + } + + fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) { + unsafe { + self.ffi_gl_.Viewport(x, y, width, height); + } + } + + fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) { + unsafe { + self.ffi_gl_.Scissor(x, y, width, height); + } + } + + fn line_width(&self, width: GLfloat) { + unsafe { + self.ffi_gl_.LineWidth(width); + } + } + + fn use_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.UseProgram(program); + } + } + + fn validate_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.ValidateProgram(program); + } + } + + fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) { + unsafe { + return self.ffi_gl_.DrawArrays(mode, first, count); + } + } + + fn draw_arrays_instanced( + &self, + mode: GLenum, + first: GLint, + count: GLsizei, + primcount: GLsizei, + ) { + unsafe { + return self + .ffi_gl_ + .DrawArraysInstanced(mode, first, count, primcount); + } + } + + fn draw_elements( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + ) { + unsafe { + return self.ffi_gl_.DrawElements( + mode, + count, + element_type, + indices_offset as *const c_void, + ); + } + } + + fn draw_elements_instanced( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + primcount: GLsizei, + ) { + unsafe { + return self.ffi_gl_.DrawElementsInstanced( + mode, + count, + element_type, + indices_offset as *const c_void, + primcount, + ); + } + } + + fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) { + unsafe { + self.ffi_gl_.BlendColor(r, g, b, a); + } + } + + fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) { + unsafe { + self.ffi_gl_.BlendFunc(sfactor, dfactor); + } + } + + fn blend_func_separate( + &self, + src_rgb: GLenum, + dest_rgb: GLenum, + src_alpha: GLenum, + dest_alpha: GLenum, + ) { + unsafe { + self.ffi_gl_ + .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha); + } + } + + fn blend_equation(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.BlendEquation(mode); + } + } + + fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) { + unsafe { + self.ffi_gl_.BlendEquationSeparate(mode_rgb, mode_alpha); + } + } + + fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) { + unsafe { + self.ffi_gl_.ColorMask( + r as GLboolean, + g as GLboolean, + b as GLboolean, + a as GLboolean, + ); + } + } + + fn cull_face(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.CullFace(mode); + } + } + + fn front_face(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.FrontFace(mode); + } + } + + fn enable(&self, cap: GLenum) { + unsafe { + self.ffi_gl_.Enable(cap); + } + } + + fn disable(&self, cap: GLenum) { + unsafe { + self.ffi_gl_.Disable(cap); + } + } + + fn hint(&self, param_name: GLenum, param_val: GLenum) { + unsafe { + self.ffi_gl_.Hint(param_name, param_val); + } + } + + fn is_enabled(&self, cap: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsEnabled(cap) } + } + + fn is_shader(&self, shader: GLuint) -> GLboolean { + unsafe { self.ffi_gl_.IsShader(shader) } + } + + fn is_texture(&self, texture: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsTexture(texture) } + } + + fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsFramebuffer(framebuffer) } + } + + fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsRenderbuffer(renderbuffer) } + } + + fn check_frame_buffer_status(&self, target: GLenum) -> GLenum { + unsafe { self.ffi_gl_.CheckFramebufferStatus(target) } + } + + fn enable_vertex_attrib_array(&self, index: GLuint) { + unsafe { + self.ffi_gl_.EnableVertexAttribArray(index); + } + } + + fn disable_vertex_attrib_array(&self, index: GLuint) { + unsafe { + self.ffi_gl_.DisableVertexAttribArray(index); + } + } + + fn uniform_1f(&self, location: GLint, v0: GLfloat) { + unsafe { + self.ffi_gl_.Uniform1f(location, v0); + } + } + + fn uniform_1fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform1fv(location, values.len() as GLsizei, values.as_ptr()); + } + } + + fn uniform_1i(&self, location: GLint, v0: GLint) { + unsafe { + self.ffi_gl_.Uniform1i(location, v0); + } + } + + fn uniform_1iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform1iv(location, values.len() as GLsizei, values.as_ptr()); + } + } + + fn uniform_1ui(&self, location: GLint, v0: GLuint) { + unsafe { + self.ffi_gl_.Uniform1ui(location, v0); + } + } + + fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) { + unsafe { + self.ffi_gl_.Uniform2f(location, v0, v1); + } + } + + fn uniform_2fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform2fv(location, (values.len() / 2) as GLsizei, values.as_ptr()); + } + } + + fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) { + unsafe { + self.ffi_gl_.Uniform2i(location, v0, v1); + } + } + + fn uniform_2iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform2iv(location, (values.len() / 2) as GLsizei, values.as_ptr()); + } + } + + fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) { + unsafe { + self.ffi_gl_.Uniform2ui(location, v0, v1); + } + } + + fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) { + unsafe { + self.ffi_gl_.Uniform3f(location, v0, v1, v2); + } + } + + fn uniform_3fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform3fv(location, (values.len() / 3) as GLsizei, values.as_ptr()); + } + } + + fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) { + unsafe { + self.ffi_gl_.Uniform3i(location, v0, v1, v2); + } + } + + fn uniform_3iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform3iv(location, (values.len() / 3) as GLsizei, values.as_ptr()); + } + } + + fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) { + unsafe { + self.ffi_gl_.Uniform3ui(location, v0, v1, v2); + } + } + + fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) { + unsafe { + self.ffi_gl_.Uniform4f(location, x, y, z, w); + } + } + + fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) { + unsafe { + self.ffi_gl_.Uniform4i(location, x, y, z, w); + } + } + + fn uniform_4iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform4iv(location, (values.len() / 4) as GLsizei, values.as_ptr()); + } + } + + fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) { + unsafe { + self.ffi_gl_.Uniform4ui(location, x, y, z, w); + } + } + + fn uniform_4fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform4fv(location, (values.len() / 4) as GLsizei, values.as_ptr()); + } + } + + fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix2fv( + location, + (value.len() / 4) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix3fv( + location, + (value.len() / 9) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix4fv( + location, + (value.len() / 16) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn depth_mask(&self, flag: bool) { + unsafe { + self.ffi_gl_.DepthMask(flag as GLboolean); + } + } + + fn depth_range(&self, near: f64, far: f64) { + unsafe { + self.ffi_gl_.DepthRange(near as GLclampd, far as GLclampd); + } + } + + fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) { + let mut buf_size = [0]; + unsafe { + self.get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH, &mut buf_size); + } + let mut name = vec![0u8; buf_size[0] as usize]; + let mut length = 0 as GLsizei; + let mut size = 0 as i32; + let mut type_ = 0 as u32; + unsafe { + self.ffi_gl_.GetActiveAttrib( + program, + index, + buf_size[0], + &mut length, + &mut size, + &mut type_, + name.as_mut_ptr() as *mut GLchar, + ); + } + name.truncate(if length > 0 { length as usize } else { 0 }); + (size, type_, String::from_utf8(name).unwrap()) + } + + fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) { + let mut buf_size = [0]; + unsafe { + self.get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH, &mut buf_size); + } + let mut name = vec![0 as u8; buf_size[0] as usize]; + let mut length: GLsizei = 0; + let mut size: i32 = 0; + let mut type_: u32 = 0; + + unsafe { + self.ffi_gl_.GetActiveUniform( + program, + index, + buf_size[0], + &mut length, + &mut size, + &mut type_, + name.as_mut_ptr() as *mut GLchar, + ); + } + + name.truncate(if length > 0 { length as usize } else { 0 }); + + (size, type_, String::from_utf8(name).unwrap()) + } + + fn get_active_uniforms_iv( + &self, + program: GLuint, + indices: Vec<GLuint>, + pname: GLenum, + ) -> Vec<GLint> { + let mut result = Vec::with_capacity(indices.len()); + unsafe { + result.set_len(indices.len()); + self.ffi_gl_.GetActiveUniformsiv( + program, + indices.len() as GLsizei, + indices.as_ptr(), + pname, + result.as_mut_ptr(), + ); + } + result + } + + fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint { + let mut result = 0; + unsafe { + self.ffi_gl_ + .GetActiveUniformBlockiv(program, index, pname, &mut result); + } + result + } + + fn get_active_uniform_block_iv( + &self, + program: GLuint, + index: GLuint, + pname: GLenum, + ) -> Vec<GLint> { + let count = + self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_ACTIVE_UNIFORMS); + let mut result = Vec::with_capacity(count as usize); + unsafe { + result.set_len(count as usize); + self.ffi_gl_ + .GetActiveUniformBlockiv(program, index, pname, result.as_mut_ptr()); + } + result + } + + fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> String { + let buf_size = + self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_NAME_LENGTH); + let mut name = vec![0 as u8; buf_size as usize]; + let mut length: GLsizei = 0; + unsafe { + self.ffi_gl_.GetActiveUniformBlockName( + program, + index, + buf_size, + &mut length, + name.as_mut_ptr() as *mut GLchar, + ); + } + name.truncate(if length > 0 { length as usize } else { 0 }); + + String::from_utf8(name).unwrap() + } + + fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int { + let name = CString::new(name).unwrap(); + unsafe { self.ffi_gl_.GetAttribLocation(program, name.as_ptr()) } + } + + fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int { + let name = CString::new(name).unwrap(); + unsafe { self.ffi_gl_.GetFragDataLocation(program, name.as_ptr()) } + } + + fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int { + let name = CString::new(name).unwrap(); + unsafe { self.ffi_gl_.GetUniformLocation(program, name.as_ptr()) } + } + + fn get_program_info_log(&self, program: GLuint) -> String { + let mut max_len = [0]; + unsafe { + self.get_program_iv(program, ffi::INFO_LOG_LENGTH, &mut max_len); + } + if max_len[0] == 0 { + return String::new(); + } + let mut result = vec![0u8; max_len[0] as usize]; + let mut result_len = 0 as GLsizei; + unsafe { + self.ffi_gl_.GetProgramInfoLog( + program, + max_len[0] as GLsizei, + &mut result_len, + result.as_mut_ptr() as *mut GLchar, + ); + } + result.truncate(if result_len > 0 { + result_len as usize + } else { + 0 + }); + String::from_utf8(result).unwrap() + } + + #[inline] + unsafe fn get_program_iv(&self, program: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetProgramiv(program, pname, result.as_mut_ptr()); + } + + fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) { + if !self.ffi_gl_.GetProgramBinary.is_loaded() { + return (Vec::new(), NONE); + } + let mut len = [0]; + unsafe { + self.get_program_iv(program, ffi::PROGRAM_BINARY_LENGTH, &mut len); + } + if len[0] <= 0 { + return (Vec::new(), NONE); + } + let mut binary: Vec<u8> = Vec::with_capacity(len[0] as usize); + let mut format = NONE; + let mut out_len = 0; + unsafe { + binary.set_len(len[0] as usize); + self.ffi_gl_.GetProgramBinary( + program, + len[0], + &mut out_len as *mut GLsizei, + &mut format, + binary.as_mut_ptr() as *mut c_void, + ); + } + if len[0] != out_len { + return (Vec::new(), NONE); + } + + (binary, format) + } + + fn program_binary(&self, program: GLuint, format: GLenum, binary: &[u8]) { + if !self.ffi_gl_.ProgramBinary.is_loaded() { + return; + } + unsafe { + self.ffi_gl_.ProgramBinary( + program, + format, + binary.as_ptr() as *const c_void, + binary.len() as GLsizei, + ); + } + } + + fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) { + if !self.ffi_gl_.ProgramParameteri.is_loaded() { + return; + } + unsafe { + self.ffi_gl_.ProgramParameteri(program, pname, value); + } + } + + #[inline] + unsafe fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetVertexAttribiv(index, pname, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetVertexAttribfv(index, pname, result.as_mut_ptr()); + } + + fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr { + let mut result = 0 as *mut GLvoid; + unsafe { + self.ffi_gl_ + .GetVertexAttribPointerv(index, pname, &mut result) + } + result as GLsizeiptr + } + + fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint { + let mut result = 0 as GLint; + unsafe { + self.ffi_gl_ + .GetBufferParameteriv(target, pname, &mut result); + } + result + } + + fn get_shader_info_log(&self, shader: GLuint) -> String { + let mut max_len = [0]; + unsafe { + self.get_shader_iv(shader, ffi::INFO_LOG_LENGTH, &mut max_len); + } + if max_len[0] == 0 { + return String::new(); + } + let mut result = vec![0u8; max_len[0] as usize]; + let mut result_len = 0 as GLsizei; + unsafe { + self.ffi_gl_.GetShaderInfoLog( + shader, + max_len[0] as GLsizei, + &mut result_len, + result.as_mut_ptr() as *mut GLchar, + ); + } + result.truncate(if result_len > 0 { + result_len as usize + } else { + 0 + }); + String::from_utf8(result).unwrap() + } + + fn get_string(&self, which: GLenum) -> String { + unsafe { + let llstr = self.ffi_gl_.GetString(which); + if !llstr.is_null() { + return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()) + .to_string(); + } else { + return "".to_string(); + } + } + } + + fn get_string_i(&self, which: GLenum, index: GLuint) -> String { + unsafe { + let llstr = self.ffi_gl_.GetStringi(which, index); + if !llstr.is_null() { + str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()) + .to_string() + } else { + "".to_string() + } + } + } + + unsafe fn get_shader_iv(&self, shader: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetShaderiv(shader, pname, result.as_mut_ptr()); + } + + fn get_shader_precision_format( + &self, + _shader_type: GLuint, + precision_type: GLuint, + ) -> (GLint, GLint, GLint) { + // gl.GetShaderPrecisionFormat is not available until OpenGL 4.1. + // Fallback to OpenGL standard precissions that most desktop hardware support. + match precision_type { + ffi::LOW_FLOAT | ffi::MEDIUM_FLOAT | ffi::HIGH_FLOAT => { + // Fallback to IEEE 754 single precision + // Range: from -2^127 to 2^127 + // Significand precision: 23 bits + (127, 127, 23) + } + ffi::LOW_INT | ffi::MEDIUM_INT | ffi::HIGH_INT => { + // Fallback to single precision integer + // Range: from -2^24 to 2^24 + // Precision: For integer formats this value is always 0 + (24, 24, 0) + } + _ => (0, 0, 0), + } + } + + fn compile_shader(&self, shader: GLuint) { + unsafe { + self.ffi_gl_.CompileShader(shader); + } + } + + fn create_program(&self) -> GLuint { + unsafe { + return self.ffi_gl_.CreateProgram(); + } + } + + fn delete_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.DeleteProgram(program); + } + } + + fn create_shader(&self, shader_type: GLenum) -> GLuint { + unsafe { + return self.ffi_gl_.CreateShader(shader_type); + } + } + + fn delete_shader(&self, shader: GLuint) { + unsafe { + self.ffi_gl_.DeleteShader(shader); + } + } + + fn detach_shader(&self, program: GLuint, shader: GLuint) { + unsafe { + self.ffi_gl_.DetachShader(program, shader); + } + } + + fn link_program(&self, program: GLuint) { + unsafe { + return self.ffi_gl_.LinkProgram(program); + } + } + + fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) { + unsafe { + self.ffi_gl_.ClearColor(r, g, b, a); + } + } + + fn clear(&self, buffer_mask: GLbitfield) { + unsafe { + self.ffi_gl_.Clear(buffer_mask); + } + } + + fn clear_depth(&self, depth: f64) { + unsafe { + self.ffi_gl_.ClearDepth(depth as GLclampd); + } + } + + fn clear_stencil(&self, s: GLint) { + unsafe { + self.ffi_gl_.ClearStencil(s); + } + } + + fn flush(&self) { + unsafe { + self.ffi_gl_.Flush(); + } + } + + fn finish(&self) { + unsafe { + self.ffi_gl_.Finish(); + } + } + + fn get_error(&self) -> GLenum { + unsafe { self.ffi_gl_.GetError() } + } + + fn stencil_mask(&self, mask: GLuint) { + unsafe { self.ffi_gl_.StencilMask(mask) } + } + + fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) { + unsafe { self.ffi_gl_.StencilMaskSeparate(face, mask) } + } + + fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) { + unsafe { self.ffi_gl_.StencilFunc(func, ref_, mask) } + } + + fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) { + unsafe { self.ffi_gl_.StencilFuncSeparate(face, func, ref_, mask) } + } + + fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) { + unsafe { self.ffi_gl_.StencilOp(sfail, dpfail, dppass) } + } + + fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) { + unsafe { self.ffi_gl_.StencilOpSeparate(face, sfail, dpfail, dppass) } + } + + #[allow(unused_variables)] + fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) { + panic!("not supported") + } + + #[allow(unused_variables)] + fn egl_image_target_renderbuffer_storage_oes(&self, target: GLenum, image: GLeglImageOES) { + panic!("not supported") + } + + fn generate_mipmap(&self, target: GLenum) { + unsafe { self.ffi_gl_.GenerateMipmap(target) } + } + + fn insert_event_marker_ext(&self, message: &str) { + if self.ffi_gl_.InsertEventMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_ + .InsertEventMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn push_group_marker_ext(&self, message: &str) { + if self.ffi_gl_.PushGroupMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_ + .PushGroupMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn pop_group_marker_ext(&self) { + if self.ffi_gl_.PopGroupMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_.PopGroupMarkerEXT(); + } + } + } + + fn debug_message_insert_khr(&self, source: GLenum, type_: GLenum, id: GLuint, severity: GLenum, message: &str) { + if self.ffi_gl_.DebugMessageInsertKHR.is_loaded() { + unsafe { + self.ffi_gl_ + .DebugMessageInsertKHR(source, type_, id, severity, message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) { + if self.ffi_gl_.PushDebugGroupKHR.is_loaded() { + unsafe { + self.ffi_gl_ + .PushDebugGroupKHR(source, id, message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn pop_debug_group_khr(&self) { + if self.ffi_gl_.PopDebugGroupKHR.is_loaded() { + unsafe { + self.ffi_gl_.PopDebugGroupKHR(); + } + } + } + + fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsync { + unsafe { self.ffi_gl_.FenceSync(condition, flags) as *const _ } + } + + fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum { + unsafe { + self.ffi_gl_ + .ClientWaitSync(sync as *const _, flags, timeout) + } + } + + fn wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) { + unsafe { + self.ffi_gl_.WaitSync(sync as *const _, flags, timeout); + } + } + + fn texture_range_apple(&self, target: GLenum, data: &[u8]) { + unsafe { + self.ffi_gl_.TextureRangeAPPLE( + target, + data.len() as GLsizei, + data.as_ptr() as *const c_void, + ); + } + } + + fn delete_sync(&self, sync: GLsync) { + unsafe { + self.ffi_gl_.DeleteSync(sync as *const _); + } + } + + fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenFencesAPPLE(n, result.as_mut_ptr()); + } + result + } + + fn delete_fences_apple(&self, fences: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteFencesAPPLE(fences.len() as GLsizei, fences.as_ptr()); + } + } + + fn set_fence_apple(&self, fence: GLuint) { + unsafe { + self.ffi_gl_.SetFenceAPPLE(fence); + } + } + + fn finish_fence_apple(&self, fence: GLuint) { + unsafe { + self.ffi_gl_.FinishFenceAPPLE(fence); + } + } + + fn test_fence_apple(&self, fence: GLuint) { + unsafe { + self.ffi_gl_.TestFenceAPPLE(fence); + } + } + + fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean { + unsafe { + self.ffi_gl_.TestObjectAPPLE(object, name) + } + } + + fn finish_object_apple(&self, object: GLenum, name: GLuint) { + unsafe { + // the spec has a typo for name as GLint instead of GLuint + self.ffi_gl_.FinishObjectAPPLE(object, name as GLint); + } + } + + // GL_ARB_blend_func_extended + fn bind_frag_data_location_indexed( + &self, + program: GLuint, + color_number: GLuint, + index: GLuint, + name: &str, + ) { + if !self.ffi_gl_.BindFragDataLocationIndexed.is_loaded() { + return; + } + + let c_string = CString::new(name).unwrap(); + + unsafe { + self.ffi_gl_.BindFragDataLocationIndexed( + program, + color_number, + index, + c_string.as_ptr(), + ) + } + } + + fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint { + if !self.ffi_gl_.GetFragDataIndex.is_loaded() { + return -1; + } + + let c_string = CString::new(name).unwrap(); + + unsafe { self.ffi_gl_.GetFragDataIndex(program, c_string.as_ptr()) } + } + + // GL_KHR_debug + fn get_debug_messages(&self) -> Vec<DebugMessage> { + if !self.ffi_gl_.GetDebugMessageLog.is_loaded() { + return Vec::new(); + } + + let mut max_message_len = 0; + unsafe { + self.ffi_gl_ + .GetIntegerv(ffi::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_len) + } + + let mut output = Vec::new(); + const CAPACITY: usize = 4; + + let mut msg_data = vec![0u8; CAPACITY * max_message_len as usize]; + let mut sources = [0 as GLenum; CAPACITY]; + let mut types = [0 as GLenum; CAPACITY]; + let mut severities = [0 as GLenum; CAPACITY]; + let mut ids = [0 as GLuint; CAPACITY]; + let mut lengths = [0 as GLsizei; CAPACITY]; + + loop { + let count = unsafe { + self.ffi_gl_.GetDebugMessageLog( + CAPACITY as _, + msg_data.len() as _, + sources.as_mut_ptr(), + types.as_mut_ptr(), + ids.as_mut_ptr(), + severities.as_mut_ptr(), + lengths.as_mut_ptr(), + msg_data.as_mut_ptr() as *mut _, + ) + }; + + let mut offset = 0; + output.extend((0..count as usize).map(|i| { + let len = lengths[i] as usize; + let slice = &msg_data[offset..offset + len]; + offset += len; + DebugMessage { + message: String::from_utf8_lossy(slice).to_string(), + source: sources[i], + ty: types[i], + id: ids[i], + severity: severities[i], + } + })); + + if (count as usize) < CAPACITY { + return output; + } + } + } + + fn provoking_vertex_angle(&self, _mode: GLenum) { + unimplemented!("This extension is GLES only"); + } + + // GL_KHR_blend_equation_advanced + fn blend_barrier_khr(&self) { + if self.ffi_gl_.BlendBarrierKHR.is_loaded() { + unsafe { + self.ffi_gl_.BlendBarrierKHR(); + } + } + } + + // GL_CHROMIUM_copy_texture + fn copy_texture_chromium(&self, + _source_id: GLuint, _source_level: GLint, + _dest_target: GLenum, _dest_id: GLuint, _dest_level: GLint, + _internal_format: GLint, _dest_type: GLenum, + _unpack_flip_y: GLboolean, _unpack_premultiply_alpha: GLboolean, _unpack_unmultiply_alpha: GLboolean) + { + unimplemented!("This extension is GLES only"); + } + fn copy_sub_texture_chromium(&self, + _source_id: GLuint, _source_level: GLint, + _dest_target: GLenum, _dest_id: GLuint, _dest_level: GLint, + _x_offset: GLint, _y_offset: GLint, _x: GLint, _y: GLint, _width: GLsizei, _height: GLsizei, + _unpack_flip_y: GLboolean, _unpack_premultiply_alpha: GLboolean, _unpack_unmultiply_alpha: GLboolean) + { + unimplemented!("This extension is GLES only"); + } + + // GL_ANGLE_copy_texture_3d + fn copy_texture_3d_angle( + &self, + _source_id: GLuint, + _source_level: GLint, + _dest_target: GLenum, + _dest_id: GLuint, + _dest_level: GLint, + _internal_format: GLint, + _dest_type: GLenum, + _unpack_flip_y: GLboolean, + _unpack_premultiply_alpha: GLboolean, + _unpack_unmultiply_alpha: GLboolean, + ) { + unimplemented!("This extension is ANGLE only"); + } + + fn copy_sub_texture_3d_angle( + &self, + _source_id: GLuint, + _source_level: GLint, + _dest_target: GLenum, + _dest_id: GLuint, + _dest_level: GLint, + _x_offset: GLint, + _y_offset: GLint, + _z_offset: GLint, + _x: GLint, + _y: GLint, + _z: GLint, + _width: GLsizei, + _height: GLsizei, + _depth: GLsizei, + _unpack_flip_y: GLboolean, + _unpack_premultiply_alpha: GLboolean, + _unpack_unmultiply_alpha: GLboolean, + ) { + unimplemented!("This extension is ANGLE only"); + } + + fn buffer_storage( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + flags: GLbitfield, + ) { + unsafe { + self.ffi_gl_.BufferStorage(target, size, data, flags); + } + } + + fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) { + unsafe { + self.ffi_gl_.FlushMappedBufferRange(target, offset, length); + } + } + + fn start_tiling_qcom(&self, _x: GLuint, _y: GLuint, _width: GLuint, _height: GLuint, _preserve_mask: GLbitfield) { + } + + fn end_tiling_qcom(&self, _preserve_mask: GLbitfield) { + } +} diff --git a/third_party/rust/gleam/src/gles_fns.rs b/third_party/rust/gleam/src/gles_fns.rs new file mode 100644 index 0000000000..ee7ea70265 --- /dev/null +++ b/third_party/rust/gleam/src/gles_fns.rs @@ -0,0 +1,2301 @@ +// Copyright 2014 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct GlesFns { + ffi_gl_: GlesFfi, +} + +impl GlesFns { + pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<dyn Gl> + where + F: FnMut(&str) -> *const c_void, + { + let ffi_gl_ = GlesFfi::load_with(loadfn); + Rc::new(GlesFns { ffi_gl_: ffi_gl_ }) as Rc<dyn Gl> + } +} + +impl Gl for GlesFns { + fn get_type(&self) -> GlType { + GlType::Gles + } + + fn buffer_data_untyped( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + usage: GLenum, + ) { + unsafe { + self.ffi_gl_.BufferData(target, size, data, usage); + } + } + + fn tex_buffer(&self, _target: GLenum, _internal_format: GLenum, _buffer: GLuint) { + panic!("not supported") + } + + fn buffer_sub_data_untyped( + &self, + target: GLenum, + offset: isize, + size: GLsizeiptr, + data: *const GLvoid, + ) { + unsafe { + self.ffi_gl_.BufferSubData(target, offset, size, data); + } + } + + fn map_buffer(&self, + _target: GLenum, + _access: GLbitfield) -> *mut c_void { + panic!("not supported") + } + + fn map_buffer_range(&self, + target: GLenum, + offset: GLintptr, + length: GLsizeiptr, + access: GLbitfield) -> *mut c_void { + unsafe { + return self.ffi_gl_.MapBufferRange(target, offset, length, access); + } + } + + fn unmap_buffer(&self, target: GLenum) -> GLboolean { + unsafe { + return self.ffi_gl_.UnmapBuffer(target); + } + } + + fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) { + let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect(); + let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect(); + unsafe { + self.ffi_gl_.ShaderSource( + shader, + pointers.len() as GLsizei, + pointers.as_ptr() as *const *const GLchar, + lengths.as_ptr(), + ); + } + drop(lengths); + drop(pointers); + } + + #[allow(unused_variables)] + fn read_buffer(&self, mode: GLenum) { + panic!("not supported") + } + + fn read_pixels_into_buffer( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + dst_buffer: &mut [u8], + ) { + // Assumes that the user properly allocated the size for dst_buffer. + let mut row_length = 0; + unsafe { + self.ffi_gl_.GetIntegerv(ffi::PACK_ROW_LENGTH, &mut row_length as _); + } + if row_length == 0 { + row_length = width; + } else { + assert!(row_length >= width); + } + assert_eq!(calculate_length(row_length, height, format, pixel_type), dst_buffer.len()); + + unsafe { + // We don't want any alignment padding on pixel rows. + self.ffi_gl_.PixelStorei(ffi::PACK_ALIGNMENT, 1); + self.ffi_gl_.ReadPixels( + x, + y, + width, + height, + format, + pixel_type, + dst_buffer.as_mut_ptr() as *mut c_void, + ); + } + } + + fn read_pixels( + &self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum, + ) -> Vec<u8> { + let len = calculate_length(width, height, format, pixel_type); + let mut pixels: Vec<u8> = Vec::new(); + pixels.reserve(len); + unsafe { + pixels.set_len(len); + } + + self.read_pixels_into_buffer( + x, + y, + width, + height, + format, + pixel_type, + pixels.as_mut_slice(), + ); + + pixels + } + + unsafe fn read_pixels_into_pbo(&self, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + pixel_type: GLenum) { + self.ffi_gl_.ReadPixels(x, y, width, height, format, pixel_type, ptr::null_mut()); + } + + fn sample_coverage(&self, value: GLclampf, invert: bool) { + unsafe { + self.ffi_gl_.SampleCoverage(value, invert as GLboolean); + } + } + + fn polygon_offset(&self, factor: GLfloat, units: GLfloat) { + unsafe { + self.ffi_gl_.PolygonOffset(factor, units); + } + } + + fn pixel_store_i(&self, name: GLenum, param: GLint) { + unsafe { + self.ffi_gl_.PixelStorei(name, param); + } + } + + fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenBuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr()); + } + result + } + + fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenTextures(n, result.as_mut_ptr()); + } + result + } + + fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> { + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr()); + } + result + } + + fn gen_vertex_arrays_apple(&self, _n: GLsizei) -> Vec<GLuint> { + panic!("not supported") + } + + fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> { + if !self.ffi_gl_.GenQueriesEXT.is_loaded() { + return Vec::new(); + } + let mut result = vec![0 as GLuint; n as usize]; + unsafe { + self.ffi_gl_.GenQueriesEXT(n, result.as_mut_ptr()); + } + result + } + + fn begin_query(&self, target: GLenum, id: GLuint) { + if !self.ffi_gl_.BeginQueryEXT.is_loaded() { + return; + } + unsafe { + self.ffi_gl_.BeginQueryEXT(target, id); + } + } + + fn end_query(&self, target: GLenum) { + if !self.ffi_gl_.EndQueryEXT.is_loaded() { + return; + } + unsafe { + self.ffi_gl_.EndQueryEXT(target); + } + } + + fn query_counter(&self, id: GLuint, target: GLenum) { + if !self.ffi_gl_.QueryCounterEXT.is_loaded() { + return; + } + unsafe { + self.ffi_gl_.QueryCounterEXT(id, target); + } + } + + fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 { + if !self.ffi_gl_.GetQueryObjectivEXT.is_loaded() { + return 0; + } + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectivEXT(id, pname, &mut result); + } + result + } + + fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 { + if !self.ffi_gl_.GetQueryObjectuivEXT.is_loaded() { + return 0; + } + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectuivEXT(id, pname, &mut result); + } + result + } + + fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 { + if !self.ffi_gl_.GetQueryObjecti64vEXT.is_loaded() { + return 0; + } + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjecti64vEXT(id, pname, &mut result); + } + result + } + + fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 { + if !self.ffi_gl_.GetQueryObjectui64vEXT.is_loaded() { + return 0; + } + let mut result = 0; + unsafe { + self.ffi_gl_.GetQueryObjectui64vEXT(id, pname, &mut result); + } + result + } + + fn delete_queries(&self, queries: &[GLuint]) { + if !self.ffi_gl_.DeleteQueriesEXT.is_loaded() { + return; + } + unsafe { + self.ffi_gl_ + .DeleteQueriesEXT(queries.len() as GLsizei, queries.as_ptr()); + } + } + + fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr()); + } + } + + fn delete_vertex_arrays_apple(&self, _vertex_arrays: &[GLuint]) { + panic!("not supported") + } + + fn delete_buffers(&self, buffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr()); + } + } + + fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr()); + } + } + + fn delete_framebuffers(&self, framebuffers: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr()); + } + } + + fn delete_textures(&self, textures: &[GLuint]) { + unsafe { + self.ffi_gl_ + .DeleteTextures(textures.len() as GLsizei, textures.as_ptr()); + } + } + + fn framebuffer_renderbuffer( + &self, + target: GLenum, + attachment: GLenum, + renderbuffertarget: GLenum, + renderbuffer: GLuint, + ) { + unsafe { + self.ffi_gl_.FramebufferRenderbuffer( + target, + attachment, + renderbuffertarget, + renderbuffer, + ); + } + } + + fn renderbuffer_storage( + &self, + target: GLenum, + internalformat: GLenum, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .RenderbufferStorage(target, internalformat, width, height); + } + } + + fn depth_func(&self, func: GLenum) { + unsafe { + self.ffi_gl_.DepthFunc(func); + } + } + + fn active_texture(&self, texture: GLenum) { + unsafe { + self.ffi_gl_.ActiveTexture(texture); + } + } + + fn attach_shader(&self, program: GLuint, shader: GLuint) { + unsafe { + self.ffi_gl_.AttachShader(program, shader); + } + } + + fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) { + let c_string = CString::new(name).unwrap(); + unsafe { + self.ffi_gl_ + .BindAttribLocation(program, index, c_string.as_ptr()) + } + } + + // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml + unsafe fn get_uniform_iv(&self, program: GLuint, location: GLint, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetUniformiv(program, location, result.as_mut_ptr()); + } + + // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml + unsafe fn get_uniform_fv(&self, program: GLuint, location: GLint, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetUniformfv(program, location, result.as_mut_ptr()); + } + + fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint { + let c_string = CString::new(name).unwrap(); + unsafe { + self.ffi_gl_ + .GetUniformBlockIndex(program, c_string.as_ptr()) + } + } + + fn get_uniform_indices(&self, program: GLuint, names: &[&str]) -> Vec<GLuint> { + let c_strings: Vec<CString> = names.iter().map(|n| CString::new(*n).unwrap()).collect(); + let pointers: Vec<*const GLchar> = c_strings.iter().map(|string| string.as_ptr()).collect(); + let mut result = Vec::with_capacity(c_strings.len()); + unsafe { + result.set_len(c_strings.len()); + self.ffi_gl_.GetUniformIndices( + program, + pointers.len() as GLsizei, + pointers.as_ptr(), + result.as_mut_ptr(), + ); + } + result + } + + fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) { + unsafe { + self.ffi_gl_.BindBufferBase(target, index, buffer); + } + } + + fn bind_buffer_range( + &self, + target: GLenum, + index: GLuint, + buffer: GLuint, + offset: GLintptr, + size: GLsizeiptr, + ) { + unsafe { + self.ffi_gl_ + .BindBufferRange(target, index, buffer, offset, size); + } + } + + fn uniform_block_binding( + &self, + program: GLuint, + uniform_block_index: GLuint, + uniform_block_binding: GLuint, + ) { + unsafe { + self.ffi_gl_ + .UniformBlockBinding(program, uniform_block_index, uniform_block_binding); + } + } + + fn bind_buffer(&self, target: GLenum, buffer: GLuint) { + unsafe { + self.ffi_gl_.BindBuffer(target, buffer); + } + } + + fn bind_vertex_array(&self, vao: GLuint) { + unsafe { + self.ffi_gl_.BindVertexArray(vao); + } + } + + fn bind_vertex_array_apple(&self, _vao: GLuint) { + panic!("not supported") + } + + fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) { + unsafe { + self.ffi_gl_.BindRenderbuffer(target, renderbuffer); + } + } + + fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) { + unsafe { + self.ffi_gl_.BindFramebuffer(target, framebuffer); + } + } + + fn bind_texture(&self, target: GLenum, texture: GLuint) { + unsafe { + self.ffi_gl_.BindTexture(target, texture); + } + } + + fn bind_vertex_buffer(&self, binding_index: GLuint, buffer: GLuint, offset: GLintptr, stride: GLint) { + unsafe { self.ffi_gl_.BindVertexBuffer(binding_index, buffer, offset, stride) } + } + + fn draw_buffers(&self, bufs: &[GLenum]) { + unsafe { + self.ffi_gl_ + .DrawBuffers(bufs.len() as GLsizei, bufs.as_ptr()); + } + } + + // FIXME: Does not verify buffer size -- unsafe! + fn tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ) { + match opt_data { + Some(data) => unsafe { + self.ffi_gl_.TexImage2D( + target, + level, + internal_format, + width, + height, + border, + format, + ty, + data.as_ptr() as *const GLvoid, + ); + }, + None => unsafe { + self.ffi_gl_.TexImage2D( + target, + level, + internal_format, + width, + height, + border, + format, + ty, + ptr::null(), + ); + }, + } + } + + fn compressed_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + border: GLint, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.CompressedTexImage2D( + target, + level, + internal_format, + width, + height, + border, + data.len() as GLsizei, + data.as_ptr() as *const GLvoid, + ); + } + } + + fn compressed_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.CompressedTexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + data.len() as GLsizei, + data.as_ptr() as *const GLvoid, + ); + } + } + + // FIXME: Does not verify buffer size -- unsafe! + fn tex_image_3d( + &self, + target: GLenum, + level: GLint, + internal_format: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + border: GLint, + format: GLenum, + ty: GLenum, + opt_data: Option<&[u8]>, + ) { + unsafe { + let pdata = match opt_data { + Some(data) => mem::transmute(data.as_ptr()), + None => ptr::null(), + }; + self.ffi_gl_.TexImage3D( + target, + level, + internal_format, + width, + height, + depth, + border, + format, + ty, + pdata, + ); + } + } + + fn copy_tex_image_2d( + &self, + target: GLenum, + level: GLint, + internal_format: GLenum, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + border: GLint, + ) { + unsafe { + self.ffi_gl_.CopyTexImage2D( + target, + level, + internal_format, + x, + y, + width, + height, + border, + ); + } + } + + fn copy_tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + } + } + + fn copy_tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + x: GLint, + y: GLint, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_.CopyTexSubImage3D( + target, level, xoffset, yoffset, zoffset, x, y, width, height, + ); + } + } + + fn tex_sub_image_2d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.TexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + ty, + data.as_ptr() as *const c_void, + ); + } + } + + fn tex_sub_image_2d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ) { + unsafe { + self.ffi_gl_.TexSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + ty, + offset as *const c_void, + ); + } + } + + fn tex_sub_image_3d( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + data: &[u8], + ) { + unsafe { + self.ffi_gl_.TexSubImage3D( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + ty, + data.as_ptr() as *const c_void, + ); + } + } + + fn tex_sub_image_3d_pbo( + &self, + target: GLenum, + level: GLint, + xoffset: GLint, + yoffset: GLint, + zoffset: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + format: GLenum, + ty: GLenum, + offset: usize, + ) { + unsafe { + self.ffi_gl_.TexSubImage3D( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + ty, + offset as *const c_void, + ); + } + } + + fn tex_storage_2d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .TexStorage2D(target, levels, internal_format, width, height); + } + } + + fn tex_storage_3d( + &self, + target: GLenum, + levels: GLint, + internal_format: GLenum, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + ) { + unsafe { + self.ffi_gl_ + .TexStorage3D(target, levels, internal_format, width, height, depth); + } + } + + #[allow(unused_variables)] + fn get_tex_image_into_buffer( + &self, + target: GLenum, + level: GLint, + format: GLenum, + ty: GLenum, + output: &mut [u8], + ) { + panic!("not supported"); + } + + unsafe fn copy_image_sub_data( + &self, + src_name: GLuint, + src_target: GLenum, + src_level: GLint, + src_x: GLint, + src_y: GLint, + src_z: GLint, + dst_name: GLuint, + dst_target: GLenum, + dst_level: GLint, + dst_x: GLint, + dst_y: GLint, + dst_z: GLint, + src_width: GLsizei, + src_height: GLsizei, + src_depth: GLsizei, + ) { + self.ffi_gl_.CopyImageSubDataEXT( + src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target, dst_level, + dst_x, dst_y, dst_z, src_width, src_height, src_depth, + ); + } + + fn invalidate_framebuffer(&self, target: GLenum, attachments: &[GLenum]) { + unsafe { + self.ffi_gl_.InvalidateFramebuffer( + target, + attachments.len() as GLsizei, + attachments.as_ptr(), + ); + } + } + + fn invalidate_sub_framebuffer( + &self, + target: GLenum, + attachments: &[GLenum], + xoffset: GLint, + yoffset: GLint, + width: GLsizei, + height: GLsizei, + ) { + unsafe { + self.ffi_gl_.InvalidateSubFramebuffer( + target, + attachments.len() as GLsizei, + attachments.as_ptr(), + xoffset, + yoffset, + width, + height, + ); + } + } + + #[inline] + unsafe fn get_integer_v(&self, name: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetIntegerv(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_64v(&self, name: GLenum, result: &mut [GLint64]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetInteger64v(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_iv(&self, name: GLenum, index: GLuint, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetIntegeri_v(name, index, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_integer_64iv(&self, name: GLenum, index: GLuint, result: &mut [GLint64]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetInteger64i_v(name, index, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_boolean_v(&self, name: GLenum, result: &mut [GLboolean]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetBooleanv(name, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_float_v(&self, name: GLenum, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetFloatv(name, result.as_mut_ptr()); + } + + fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_ + .GetRenderbufferParameteriv(target, pname, &mut result); + } + result + } + + fn get_framebuffer_attachment_parameter_iv( + &self, + target: GLenum, + attachment: GLenum, + pname: GLenum, + ) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_.GetFramebufferAttachmentParameteriv( + target, + attachment, + pname, + &mut result, + ); + } + result + } + + fn get_tex_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint { + let mut result: GLint = 0; + unsafe { + self.ffi_gl_.GetTexParameteriv(target, pname, &mut result); + } + result + } + + fn get_tex_parameter_fv(&self, target: GLenum, pname: GLenum) -> GLfloat { + let mut result: GLfloat = 0.0; + unsafe { + self.ffi_gl_.GetTexParameterfv(target, pname, &mut result); + } + result + } + + fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) { + unsafe { + self.ffi_gl_.TexParameteri(target, pname, param); + } + } + + fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) { + unsafe { + self.ffi_gl_.TexParameterf(target, pname, param); + } + } + + fn framebuffer_texture_2d( + &self, + target: GLenum, + attachment: GLenum, + textarget: GLenum, + texture: GLuint, + level: GLint, + ) { + unsafe { + self.ffi_gl_ + .FramebufferTexture2D(target, attachment, textarget, texture, level); + } + } + + fn framebuffer_texture_layer( + &self, + target: GLenum, + attachment: GLenum, + texture: GLuint, + level: GLint, + layer: GLint, + ) { + unsafe { + self.ffi_gl_ + .FramebufferTextureLayer(target, attachment, texture, level, layer); + } + } + + fn blit_framebuffer( + &self, + src_x0: GLint, + src_y0: GLint, + src_x1: GLint, + src_y1: GLint, + dst_x0: GLint, + dst_y0: GLint, + dst_x1: GLint, + dst_y1: GLint, + mask: GLbitfield, + filter: GLenum, + ) { + unsafe { + self.ffi_gl_.BlitFramebuffer( + src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter, + ); + } + } + + fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) { + unsafe { self.ffi_gl_.VertexAttrib4f(index, x, y, z, w) } + } + + fn vertex_attrib_binding(&self, attrib_index: GLuint, binding_index: GLuint) { + unsafe { self.ffi_gl_.VertexAttribBinding(attrib_index, binding_index) } + } + + fn vertex_attrib_pointer_f32( + &self, + index: GLuint, + size: GLint, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_.VertexAttribPointer( + index, + size, + ffi::FLOAT, + normalized as GLboolean, + stride, + offset as *const GLvoid, + ) + } + } + + fn vertex_attrib_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + normalized: bool, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_.VertexAttribPointer( + index, + size, + type_, + normalized as GLboolean, + stride, + offset as *const GLvoid, + ) + } + } + + fn vertex_attrib_i_pointer( + &self, + index: GLuint, + size: GLint, + type_: GLenum, + stride: GLsizei, + offset: GLuint, + ) { + unsafe { + self.ffi_gl_ + .VertexAttribIPointer(index, size, type_, stride, offset as *const GLvoid) + } + } + + fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) { + unsafe { self.ffi_gl_.VertexAttribDivisor(index, divisor) } + } + + fn vertex_attrib_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, normalized: bool, relative_offset: GLuint) { + unsafe { self.ffi_gl_.VertexAttribFormat(attrib_index, size, type_, normalized as GLboolean, relative_offset) } + } + + fn vertex_attrib_i_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, relative_offset: GLuint) { + unsafe { self.ffi_gl_.VertexAttribIFormat(attrib_index, size, type_, relative_offset) } + } + + fn vertex_binding_divisor(&self, binding_index: GLuint, divisor: GLuint) { + unsafe { self.ffi_gl_.VertexBindingDivisor(binding_index, divisor) } + } + + fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) { + unsafe { + self.ffi_gl_.Viewport(x, y, width, height); + } + } + + fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) { + unsafe { + self.ffi_gl_.Scissor(x, y, width, height); + } + } + + fn line_width(&self, width: GLfloat) { + unsafe { + self.ffi_gl_.LineWidth(width); + } + } + + fn use_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.UseProgram(program); + } + } + + fn validate_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.ValidateProgram(program); + } + } + + fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) { + unsafe { + return self.ffi_gl_.DrawArrays(mode, first, count); + } + } + + fn draw_arrays_instanced( + &self, + mode: GLenum, + first: GLint, + count: GLsizei, + primcount: GLsizei, + ) { + unsafe { + return self + .ffi_gl_ + .DrawArraysInstanced(mode, first, count, primcount); + } + } + + fn draw_elements( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + ) { + unsafe { + return self.ffi_gl_.DrawElements( + mode, + count, + element_type, + indices_offset as *const c_void, + ); + } + } + + fn draw_elements_instanced( + &self, + mode: GLenum, + count: GLsizei, + element_type: GLenum, + indices_offset: GLuint, + primcount: GLsizei, + ) { + unsafe { + return self.ffi_gl_.DrawElementsInstanced( + mode, + count, + element_type, + indices_offset as *const c_void, + primcount, + ); + } + } + + fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) { + unsafe { + self.ffi_gl_.BlendColor(r, g, b, a); + } + } + + fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) { + unsafe { + self.ffi_gl_.BlendFunc(sfactor, dfactor); + } + } + + fn blend_func_separate( + &self, + src_rgb: GLenum, + dest_rgb: GLenum, + src_alpha: GLenum, + dest_alpha: GLenum, + ) { + unsafe { + self.ffi_gl_ + .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha); + } + } + + fn blend_equation(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.BlendEquation(mode); + } + } + + fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) { + unsafe { + self.ffi_gl_.BlendEquationSeparate(mode_rgb, mode_alpha); + } + } + + fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) { + unsafe { + self.ffi_gl_.ColorMask( + r as GLboolean, + g as GLboolean, + b as GLboolean, + a as GLboolean, + ); + } + } + + fn cull_face(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.CullFace(mode); + } + } + + fn front_face(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.FrontFace(mode); + } + } + + fn enable(&self, cap: GLenum) { + unsafe { + self.ffi_gl_.Enable(cap); + } + } + + fn disable(&self, cap: GLenum) { + unsafe { + self.ffi_gl_.Disable(cap); + } + } + + fn hint(&self, param_name: GLenum, param_val: GLenum) { + unsafe { + self.ffi_gl_.Hint(param_name, param_val); + } + } + + fn is_enabled(&self, cap: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsEnabled(cap) } + } + + fn is_shader(&self, shader: GLuint) -> GLboolean { + unsafe { self.ffi_gl_.IsShader(shader) } + } + + fn is_texture(&self, texture: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsTexture(texture) } + } + + fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsFramebuffer(framebuffer) } + } + + fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean { + unsafe { self.ffi_gl_.IsRenderbuffer(renderbuffer) } + } + + fn check_frame_buffer_status(&self, target: GLenum) -> GLenum { + unsafe { self.ffi_gl_.CheckFramebufferStatus(target) } + } + + fn enable_vertex_attrib_array(&self, index: GLuint) { + unsafe { + self.ffi_gl_.EnableVertexAttribArray(index); + } + } + + fn disable_vertex_attrib_array(&self, index: GLuint) { + unsafe { + self.ffi_gl_.DisableVertexAttribArray(index); + } + } + + fn uniform_1f(&self, location: GLint, v0: GLfloat) { + unsafe { + self.ffi_gl_.Uniform1f(location, v0); + } + } + + fn uniform_1fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform1fv(location, values.len() as GLsizei, values.as_ptr()); + } + } + + fn uniform_1i(&self, location: GLint, v0: GLint) { + unsafe { + self.ffi_gl_.Uniform1i(location, v0); + } + } + + fn uniform_1iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform1iv(location, values.len() as GLsizei, values.as_ptr()); + } + } + + #[allow(unused_variables)] + fn uniform_1ui(&self, location: GLint, v0: GLuint) { + panic!("not supported") + } + + fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) { + unsafe { + self.ffi_gl_.Uniform2f(location, v0, v1); + } + } + + fn uniform_2fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform2fv(location, (values.len() / 2) as GLsizei, values.as_ptr()); + } + } + + fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) { + unsafe { + self.ffi_gl_.Uniform2i(location, v0, v1); + } + } + + fn uniform_2iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform2iv(location, (values.len() / 2) as GLsizei, values.as_ptr()); + } + } + + #[allow(unused_variables)] + fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) { + panic!("not supported") + } + + fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) { + unsafe { + self.ffi_gl_.Uniform3f(location, v0, v1, v2); + } + } + + fn uniform_3fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform3fv(location, (values.len() / 3) as GLsizei, values.as_ptr()); + } + } + + fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) { + unsafe { + self.ffi_gl_.Uniform3i(location, v0, v1, v2); + } + } + + fn uniform_3iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform3iv(location, (values.len() / 3) as GLsizei, values.as_ptr()); + } + } + + #[allow(unused_variables)] + fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) { + panic!("not supported") + } + + fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) { + unsafe { + self.ffi_gl_.Uniform4f(location, x, y, z, w); + } + } + + fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) { + unsafe { + self.ffi_gl_.Uniform4i(location, x, y, z, w); + } + } + + fn uniform_4iv(&self, location: GLint, values: &[i32]) { + unsafe { + self.ffi_gl_ + .Uniform4iv(location, (values.len() / 4) as GLsizei, values.as_ptr()); + } + } + + #[allow(unused_variables)] + fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) { + panic!("not supported") + } + + fn uniform_4fv(&self, location: GLint, values: &[f32]) { + unsafe { + self.ffi_gl_ + .Uniform4fv(location, (values.len() / 4) as GLsizei, values.as_ptr()); + } + } + + fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix2fv( + location, + (value.len() / 4) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix3fv( + location, + (value.len() / 9) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) { + unsafe { + self.ffi_gl_.UniformMatrix4fv( + location, + (value.len() / 16) as GLsizei, + transpose as GLboolean, + value.as_ptr(), + ); + } + } + + fn depth_mask(&self, flag: bool) { + unsafe { + self.ffi_gl_.DepthMask(flag as GLboolean); + } + } + + fn depth_range(&self, near: f64, far: f64) { + unsafe { + self.ffi_gl_.DepthRangef(near as GLclampf, far as GLclampf); + } + } + + fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) { + let mut buf_size = [0]; + unsafe { + self.get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH, &mut buf_size); + } + let mut name = vec![0u8; buf_size[0] as usize]; + let mut length = 0 as GLsizei; + let mut size = 0 as i32; + let mut type_ = 0 as u32; + unsafe { + self.ffi_gl_.GetActiveAttrib( + program, + index, + buf_size[0], + &mut length, + &mut size, + &mut type_, + name.as_mut_ptr() as *mut GLchar, + ); + } + name.truncate(if length > 0 { length as usize } else { 0 }); + (size, type_, String::from_utf8(name).unwrap()) + } + + fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) { + let mut buf_size = [0]; + unsafe { + self.get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH, &mut buf_size); + } + let mut name = vec![0 as u8; buf_size[0] as usize]; + let mut length: GLsizei = 0; + let mut size: i32 = 0; + let mut type_: u32 = 0; + + unsafe { + self.ffi_gl_.GetActiveUniform( + program, + index, + buf_size[0], + &mut length, + &mut size, + &mut type_, + name.as_mut_ptr() as *mut GLchar, + ); + } + + name.truncate(if length > 0 { length as usize } else { 0 }); + + (size, type_, String::from_utf8(name).unwrap()) + } + + fn get_active_uniforms_iv( + &self, + program: GLuint, + indices: Vec<GLuint>, + pname: GLenum, + ) -> Vec<GLint> { + let mut result = Vec::with_capacity(indices.len()); + unsafe { + result.set_len(indices.len()); + self.ffi_gl_.GetActiveUniformsiv( + program, + indices.len() as GLsizei, + indices.as_ptr(), + pname, + result.as_mut_ptr(), + ); + } + result + } + + fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint { + let mut result = 0 as GLint; + unsafe { + self.ffi_gl_ + .GetActiveUniformBlockiv(program, index, pname, &mut result); + } + result + } + + fn get_active_uniform_block_iv( + &self, + program: GLuint, + index: GLuint, + pname: GLenum, + ) -> Vec<GLint> { + let count = + self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_ACTIVE_UNIFORMS); + let mut result = Vec::with_capacity(count as usize); + unsafe { + result.set_len(count as usize); + self.ffi_gl_ + .GetActiveUniformBlockiv(program, index, pname, result.as_mut_ptr()); + } + result + } + + fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> String { + let buf_size = + self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_NAME_LENGTH); + let mut name = vec![0 as u8; buf_size as usize]; + let mut length: GLsizei = 0; + unsafe { + self.ffi_gl_.GetActiveUniformBlockName( + program, + index, + buf_size, + &mut length, + name.as_mut_ptr() as *mut GLchar, + ); + } + name.truncate(if length > 0 { length as usize } else { 0 }); + + String::from_utf8(name).unwrap() + } + + fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int { + let name = CString::new(name).unwrap(); + unsafe { self.ffi_gl_.GetAttribLocation(program, name.as_ptr()) } + } + + #[allow(unused_variables)] + fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int { + panic!("not supported") + } + + fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int { + let name = CString::new(name).unwrap(); + unsafe { self.ffi_gl_.GetUniformLocation(program, name.as_ptr()) } + } + + fn get_program_info_log(&self, program: GLuint) -> String { + let mut max_len = [0]; + unsafe { + self.get_program_iv(program, ffi::INFO_LOG_LENGTH, &mut max_len); + } + if max_len[0] == 0 { + return String::new(); + } + let mut result = vec![0u8; max_len[0] as usize]; + let mut result_len = 0 as GLsizei; + unsafe { + self.ffi_gl_.GetProgramInfoLog( + program, + max_len[0] as GLsizei, + &mut result_len, + result.as_mut_ptr() as *mut GLchar, + ); + } + result.truncate(if result_len > 0 { + result_len as usize + } else { + 0 + }); + String::from_utf8(result).unwrap() + } + + #[inline] + unsafe fn get_program_iv(&self, program: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetProgramiv(program, pname, result.as_mut_ptr()); + } + + fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) { + let mut len = [0]; + unsafe { + self.get_program_iv(program, ffi::PROGRAM_BINARY_LENGTH, &mut len); + } + if len[0] <= 0 { + return (Vec::new(), NONE); + } + let mut binary: Vec<u8> = Vec::with_capacity(len[0] as usize); + let mut format = NONE; + let mut out_len = 0; + unsafe { + binary.set_len(len[0] as usize); + self.ffi_gl_.GetProgramBinary( + program, + len[0], + &mut out_len as *mut GLsizei, + &mut format, + binary.as_mut_ptr() as *mut c_void, + ); + } + if len[0] != out_len { + return (Vec::new(), NONE); + } + + (binary, format) + } + + fn program_binary(&self, program: GLuint, format: GLenum, binary: &[u8]) { + unsafe { + self.ffi_gl_.ProgramBinary( + program, + format, + binary.as_ptr() as *const c_void, + binary.len() as GLsizei, + ); + } + } + + fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) { + unsafe { + self.ffi_gl_.ProgramParameteri(program, pname, value); + } + } + + #[inline] + unsafe fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetVertexAttribiv(index, pname, result.as_mut_ptr()); + } + + #[inline] + unsafe fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, result: &mut [GLfloat]) { + assert!(!result.is_empty()); + self.ffi_gl_ + .GetVertexAttribfv(index, pname, result.as_mut_ptr()); + } + + fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr { + let mut result = 0 as *mut GLvoid; + unsafe { + self.ffi_gl_ + .GetVertexAttribPointerv(index, pname, &mut result) + } + result as GLsizeiptr + } + + fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint { + let mut result = 0 as GLint; + unsafe { + self.ffi_gl_ + .GetBufferParameteriv(target, pname, &mut result); + } + result + } + + fn get_shader_info_log(&self, shader: GLuint) -> String { + let mut max_len = [0]; + unsafe { + self.get_shader_iv(shader, ffi::INFO_LOG_LENGTH, &mut max_len); + } + if max_len[0] == 0 { + return String::new(); + } + let mut result = vec![0u8; max_len[0] as usize]; + let mut result_len = 0 as GLsizei; + unsafe { + self.ffi_gl_.GetShaderInfoLog( + shader, + max_len[0] as GLsizei, + &mut result_len, + result.as_mut_ptr() as *mut GLchar, + ); + } + result.truncate(if result_len > 0 { + result_len as usize + } else { + 0 + }); + String::from_utf8(result).unwrap() + } + + fn get_string(&self, which: GLenum) -> String { + unsafe { + let llstr = self.ffi_gl_.GetString(which); + if !llstr.is_null() { + return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()) + .to_string(); + } else { + return "".to_string(); + } + } + } + + fn get_string_i(&self, which: GLenum, index: GLuint) -> String { + unsafe { + let llstr = self.ffi_gl_.GetStringi(which, index); + if !llstr.is_null() { + str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()) + .to_string() + } else { + "".to_string() + } + } + } + + unsafe fn get_shader_iv(&self, shader: GLuint, pname: GLenum, result: &mut [GLint]) { + assert!(!result.is_empty()); + self.ffi_gl_.GetShaderiv(shader, pname, result.as_mut_ptr()); + } + + fn get_shader_precision_format( + &self, + shader_type: GLuint, + precision_type: GLuint, + ) -> (GLint, GLint, GLint) { + let (mut range, mut precision) = match precision_type { + // These values are for a 32-bit twos-complement integer format. + ffi::LOW_INT | ffi::MEDIUM_INT | ffi::HIGH_INT => ([31, 30], 0), + + // These values are for an IEEE single-precision floating-point format. + ffi::LOW_FLOAT | ffi::MEDIUM_FLOAT | ffi::HIGH_FLOAT => ([127, 127], 23), + + _ => unreachable!("invalid precision"), + }; + // This function is sometimes defined even though it's really just + // a stub, so we need to set range and precision as if it weren't + // defined before calling it. Suppress any error that might occur. + unsafe { + self.ffi_gl_.GetShaderPrecisionFormat( + shader_type, + precision_type, + range.as_mut_ptr(), + &mut precision, + ); + let _ = self.ffi_gl_.GetError(); + } + + (range[0], range[1], precision) + } + + fn compile_shader(&self, shader: GLuint) { + unsafe { + self.ffi_gl_.CompileShader(shader); + } + } + + fn create_program(&self) -> GLuint { + unsafe { + return self.ffi_gl_.CreateProgram(); + } + } + + fn delete_program(&self, program: GLuint) { + unsafe { + self.ffi_gl_.DeleteProgram(program); + } + } + + fn create_shader(&self, shader_type: GLenum) -> GLuint { + unsafe { + return self.ffi_gl_.CreateShader(shader_type); + } + } + + fn delete_shader(&self, shader: GLuint) { + unsafe { + self.ffi_gl_.DeleteShader(shader); + } + } + + fn detach_shader(&self, program: GLuint, shader: GLuint) { + unsafe { + self.ffi_gl_.DetachShader(program, shader); + } + } + + fn link_program(&self, program: GLuint) { + unsafe { + return self.ffi_gl_.LinkProgram(program); + } + } + + fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) { + unsafe { + self.ffi_gl_.ClearColor(r, g, b, a); + } + } + + fn clear(&self, buffer_mask: GLbitfield) { + unsafe { + self.ffi_gl_.Clear(buffer_mask); + } + } + + fn clear_depth(&self, depth: f64) { + unsafe { + self.ffi_gl_.ClearDepthf(depth as GLclampf); + } + } + + fn clear_stencil(&self, s: GLint) { + unsafe { + self.ffi_gl_.ClearStencil(s); + } + } + + fn flush(&self) { + unsafe { + self.ffi_gl_.Flush(); + } + } + + fn finish(&self) { + unsafe { + self.ffi_gl_.Finish(); + } + } + + fn get_error(&self) -> GLenum { + unsafe { self.ffi_gl_.GetError() } + } + + fn stencil_mask(&self, mask: GLuint) { + unsafe { self.ffi_gl_.StencilMask(mask) } + } + + fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) { + unsafe { self.ffi_gl_.StencilMaskSeparate(face, mask) } + } + + fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) { + unsafe { self.ffi_gl_.StencilFunc(func, ref_, mask) } + } + + fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) { + unsafe { self.ffi_gl_.StencilFuncSeparate(face, func, ref_, mask) } + } + + fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) { + unsafe { self.ffi_gl_.StencilOp(sfail, dpfail, dppass) } + } + + fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) { + unsafe { self.ffi_gl_.StencilOpSeparate(face, sfail, dpfail, dppass) } + } + + fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) { + unsafe { + self.ffi_gl_.EGLImageTargetTexture2DOES(target, image); + } + } + + fn egl_image_target_renderbuffer_storage_oes(&self, target: GLenum, image: GLeglImageOES) { + unsafe { + self.ffi_gl_.EGLImageTargetRenderbufferStorageOES(target, image); + } + } + + fn generate_mipmap(&self, target: GLenum) { + unsafe { self.ffi_gl_.GenerateMipmap(target) } + } + + fn insert_event_marker_ext(&self, message: &str) { + if self.ffi_gl_.InsertEventMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_ + .InsertEventMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn push_group_marker_ext(&self, message: &str) { + if self.ffi_gl_.PushGroupMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_ + .PushGroupMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn pop_group_marker_ext(&self) { + if self.ffi_gl_.PopGroupMarkerEXT.is_loaded() { + unsafe { + self.ffi_gl_.PopGroupMarkerEXT(); + } + } + } + + fn debug_message_insert_khr(&self, source: GLenum, type_: GLenum, id: GLuint, severity: GLenum, message: &str) { + if self.ffi_gl_.DebugMessageInsertKHR.is_loaded() { + unsafe { + self.ffi_gl_ + .DebugMessageInsertKHR(source, type_, id, severity, message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) { + if self.ffi_gl_.PushDebugGroupKHR.is_loaded() { + unsafe { + self.ffi_gl_ + .PushDebugGroupKHR(source, id, message.len() as GLsizei, message.as_ptr() as *const _); + } + } + } + + fn pop_debug_group_khr(&self) { + if self.ffi_gl_.PopDebugGroupKHR.is_loaded() { + unsafe { + self.ffi_gl_.PopDebugGroupKHR(); + } + } + } + + fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsync { + unsafe { self.ffi_gl_.FenceSync(condition, flags) as *const _ } + } + + fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum { + unsafe { + self.ffi_gl_ + .ClientWaitSync(sync as *const _, flags, timeout) + } + } + + fn wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) { + unsafe { + self.ffi_gl_.WaitSync(sync as *const _, flags, timeout); + } + } + + fn delete_sync(&self, sync: GLsync) { + unsafe { + self.ffi_gl_.DeleteSync(sync as *const _); + } + } + + fn texture_range_apple(&self, _target: GLenum, _data: &[u8]) { + panic!("not supported") + } + + fn gen_fences_apple(&self, _n: GLsizei) -> Vec<GLuint> { + panic!("not supported") + } + + fn delete_fences_apple(&self, _fences: &[GLuint]) { + panic!("not supported") + } + + fn set_fence_apple(&self, _fence: GLuint) { + panic!("not supported") + } + + fn finish_fence_apple(&self, _fence: GLuint) { + panic!("not supported") + } + + fn test_fence_apple(&self, _fence: GLuint) { + panic!("not supported") + } + + fn test_object_apple(&self, _object: GLenum, _name: GLuint) -> GLboolean { + panic!("not supported") + } + + fn finish_object_apple(&self, _object: GLenum, _name: GLuint) { + panic!("not supported") + } + + + + // GL_ARB_blend_func_extended + fn bind_frag_data_location_indexed( + &self, + _program: GLuint, + _color_number: GLuint, + _index: GLuint, + _name: &str, + ) { + panic!("not supported"); + } + + fn get_frag_data_index(&self, _program: GLuint, _name: &str) -> GLint { + panic!("not supported"); + } + + // GL_KHR_debug + fn get_debug_messages(&self) -> Vec<DebugMessage> { + if !self.ffi_gl_.GetDebugMessageLog.is_loaded() { + return Vec::new(); + } + + let mut max_message_len = 0; + unsafe { + self.ffi_gl_ + .GetIntegerv(ffi::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_len) + } + + let mut output = Vec::new(); + const CAPACITY: usize = 4; + + let mut msg_data = vec![0u8; CAPACITY * max_message_len as usize]; + let mut sources = [0 as GLenum; CAPACITY]; + let mut types = [0 as GLenum; CAPACITY]; + let mut severities = [0 as GLenum; CAPACITY]; + let mut ids = [0 as GLuint; CAPACITY]; + let mut lengths = [0 as GLsizei; CAPACITY]; + + loop { + let count = unsafe { + self.ffi_gl_.GetDebugMessageLog( + CAPACITY as _, + msg_data.len() as _, + sources.as_mut_ptr(), + types.as_mut_ptr(), + ids.as_mut_ptr(), + severities.as_mut_ptr(), + lengths.as_mut_ptr(), + msg_data.as_mut_ptr() as *mut _, + ) + }; + + let mut offset = 0; + output.extend((0..count as usize).map(|i| { + let len = lengths[i] as usize; + let slice = &msg_data[offset..offset + len]; + offset += len; + DebugMessage { + message: String::from_utf8_lossy(slice).to_string(), + source: sources[i], + ty: types[i], + id: ids[i], + severity: severities[i], + } + })); + + if (count as usize) < CAPACITY { + return output; + } + } + } + + fn provoking_vertex_angle(&self, mode: GLenum) { + unsafe { + self.ffi_gl_.ProvokingVertexANGLE(mode); + } + } + + // GL_KHR_blend_equation_advanced + fn blend_barrier_khr(&self) { + if self.ffi_gl_.BlendBarrierKHR.is_loaded() { + unsafe { + self.ffi_gl_.BlendBarrierKHR(); + } + } + } + + // GL_CHROMIUM_copy_texture + fn copy_texture_chromium(&self, + source_id: GLuint, source_level: GLint, + dest_target: GLenum, dest_id: GLuint, dest_level: GLint, + internal_format: GLint, dest_type: GLenum, + unpack_flip_y: GLboolean, unpack_premultiply_alpha: GLboolean, unpack_unmultiply_alpha: GLboolean) + { + unsafe { + self.ffi_gl_.CopyTextureCHROMIUM(source_id, source_level, dest_target, dest_id, dest_level, + internal_format, dest_type, + unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha, + ); + } + } + fn copy_sub_texture_chromium(&self, + source_id: GLuint, source_level: GLint, + dest_target: GLenum, dest_id: GLuint, dest_level: GLint, + x_offset: GLint, y_offset: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei, + unpack_flip_y: GLboolean, unpack_premultiply_alpha: GLboolean, unpack_unmultiply_alpha: GLboolean) + { + unsafe { + self.ffi_gl_.CopySubTextureCHROMIUM(source_id, source_level, dest_target, dest_id, dest_level, + x_offset, y_offset, x, y, width, height, + unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha, + ); + } + } + + // GL_ANGLE_copy_texture_3d + fn copy_texture_3d_angle( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + internal_format: GLint, + dest_type: GLenum, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ) { + unsafe { + self.ffi_gl_.CopyTexture3DANGLE( + source_id, + source_level, + dest_target, + dest_id, + dest_level, + internal_format, + dest_type, + unpack_flip_y, + unpack_premultiply_alpha, + unpack_unmultiply_alpha, + ); + } + } + + fn copy_sub_texture_3d_angle( + &self, + source_id: GLuint, + source_level: GLint, + dest_target: GLenum, + dest_id: GLuint, + dest_level: GLint, + x_offset: GLint, + y_offset: GLint, + z_offset: GLint, + x: GLint, + y: GLint, + z: GLint, + width: GLsizei, + height: GLsizei, + depth: GLsizei, + unpack_flip_y: GLboolean, + unpack_premultiply_alpha: GLboolean, + unpack_unmultiply_alpha: GLboolean, + ) { + unsafe { + self.ffi_gl_.CopySubTexture3DANGLE( + source_id, + source_level, + dest_target, + dest_id, + dest_level, + x_offset, + y_offset, + z_offset, + x, + y, + z, + width, + height, + depth, + unpack_flip_y, + unpack_premultiply_alpha, + unpack_unmultiply_alpha, + ); + } + } + + fn buffer_storage( + &self, + target: GLenum, + size: GLsizeiptr, + data: *const GLvoid, + flags: GLbitfield, + ) { + unsafe { + self.ffi_gl_.BufferStorageEXT(target, size, data, flags); + } + } + + fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) { + unsafe { + self.ffi_gl_.FlushMappedBufferRange(target, offset, length); + } + } + + fn start_tiling_qcom(&self, x: GLuint, y: GLuint, width: GLuint, height: GLuint, preserve_mask: GLbitfield) { + unsafe { + self.ffi_gl_.StartTilingQCOM(x, y, width, height, preserve_mask); + } + } + + fn end_tiling_qcom(&self, preserve_mask: GLbitfield) { + unsafe { + self.ffi_gl_.EndTilingQCOM(preserve_mask); + } + } +} diff --git a/third_party/rust/gleam/src/lib.rs b/third_party/rust/gleam/src/lib.rs new file mode 100644 index 0000000000..aebb612368 --- /dev/null +++ b/third_party/rust/gleam/src/lib.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "gleam"] +#![crate_type = "lib"] + +pub mod gl; + +mod ffi { + include!(concat!(env!("OUT_DIR"), "/gl_and_gles_bindings.rs")); +} + +mod ffi_gl { + include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); +} + +mod ffi_gles { + include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs")); +} |