summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gleam
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/gleam
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/gleam')
-rw-r--r--third_party/rust/gleam/.cargo-checksum.json1
-rw-r--r--third_party/rust/gleam/COPYING5
-rw-r--r--third_party/rust/gleam/Cargo.toml24
-rw-r--r--third_party/rust/gleam/LICENSE-APACHE201
-rw-r--r--third_party/rust/gleam/LICENSE-MIT25
-rw-r--r--third_party/rust/gleam/README.md6
-rw-r--r--third_party/rust/gleam/build.rs88
-rw-r--r--third_party/rust/gleam/rustfmt.toml0
-rw-r--r--third_party/rust/gleam/src/gl.rs841
-rw-r--r--third_party/rust/gleam/src/gl_fns.rs2293
-rw-r--r--third_party/rust/gleam/src/gles_fns.rs2301
-rw-r--r--third_party/rust/gleam/src/lib.rs25
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"));
+}