gleam/
gl_fns.rs

1// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10pub struct GlFns {
11    ffi_gl_: GlFfi,
12}
13
14impl GlFns {
15    pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<dyn Gl>
16    where
17        F: FnMut(&str) -> *const c_void,
18    {
19        let ffi_gl_ = GlFfi::load_with(loadfn);
20        Rc::new(GlFns { ffi_gl_: ffi_gl_ }) as Rc<dyn Gl>
21    }
22}
23
24impl Gl for GlFns {
25    fn get_type(&self) -> GlType {
26        GlType::Gl
27    }
28
29    fn buffer_data_untyped(
30        &self,
31        target: GLenum,
32        size: GLsizeiptr,
33        data: *const GLvoid,
34        usage: GLenum,
35    ) {
36        unsafe {
37            self.ffi_gl_.BufferData(target, size, data, usage);
38        }
39    }
40
41    fn buffer_sub_data_untyped(
42        &self,
43        target: GLenum,
44        offset: isize,
45        size: GLsizeiptr,
46        data: *const GLvoid,
47    ) {
48        unsafe {
49            self.ffi_gl_.BufferSubData(target, offset, size, data);
50        }
51    }
52
53    fn map_buffer(&self,
54                  target: GLenum,
55                  access: GLbitfield) -> *mut c_void {
56        unsafe {
57            return self.ffi_gl_.MapBuffer(target, access);
58        }
59    }
60
61    fn map_buffer_range(&self,
62                        target: GLenum,
63                        offset: GLintptr,
64                        length: GLsizeiptr,
65                        access: GLbitfield) -> *mut c_void {
66        unsafe {
67            return self.ffi_gl_.MapBufferRange(target, offset, length, access);
68        }
69    }
70
71    fn unmap_buffer(&self, target: GLenum) -> GLboolean {
72        unsafe {
73            return self.ffi_gl_.UnmapBuffer(target);
74        }
75    }
76
77    fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) {
78        let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect();
79        let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect();
80        unsafe {
81            self.ffi_gl_.ShaderSource(
82                shader,
83                pointers.len() as GLsizei,
84                pointers.as_ptr() as *const *const GLchar,
85                lengths.as_ptr(),
86            );
87        }
88        drop(lengths);
89        drop(pointers);
90    }
91
92    fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) {
93        unsafe {
94            self.ffi_gl_.TexBuffer(target, internal_format, buffer);
95        }
96    }
97
98    fn read_buffer(&self, mode: GLenum) {
99        unsafe {
100            self.ffi_gl_.ReadBuffer(mode);
101        }
102    }
103
104    fn read_pixels_into_buffer(
105        &self,
106        x: GLint,
107        y: GLint,
108        width: GLsizei,
109        height: GLsizei,
110        format: GLenum,
111        pixel_type: GLenum,
112        dst_buffer: &mut [u8],
113    ) {
114        // Assumes that the user properly allocated the size for dst_buffer.
115        let mut row_length = 0;
116        unsafe {
117            self.ffi_gl_.GetIntegerv(ffi::PACK_ROW_LENGTH, &mut row_length as _);
118        }
119        if row_length == 0 {
120            row_length = width;
121        } else {
122            assert!(row_length >= width);
123        }
124        assert_eq!(calculate_length(row_length, height, format, pixel_type), dst_buffer.len());
125
126        unsafe {
127            // We don't want any alignment padding on pixel rows.
128            self.ffi_gl_.PixelStorei(ffi::PACK_ALIGNMENT, 1);
129            self.ffi_gl_.ReadPixels(
130                x,
131                y,
132                width,
133                height,
134                format,
135                pixel_type,
136                dst_buffer.as_mut_ptr() as *mut c_void,
137            );
138        }
139    }
140
141    fn read_pixels(
142        &self,
143        x: GLint,
144        y: GLint,
145        width: GLsizei,
146        height: GLsizei,
147        format: GLenum,
148        pixel_type: GLenum,
149    ) -> Vec<u8> {
150        let len = calculate_length(width, height, format, pixel_type);
151        let mut pixels: Vec<u8> = Vec::new();
152        pixels.reserve(len);
153        unsafe {
154            pixels.set_len(len);
155        }
156
157        self.read_pixels_into_buffer(
158            x,
159            y,
160            width,
161            height,
162            format,
163            pixel_type,
164            pixels.as_mut_slice(),
165        );
166
167        pixels
168    }
169
170    unsafe fn read_pixels_into_pbo(&self,
171                            x: GLint,
172                            y: GLint,
173                            width: GLsizei,
174                            height: GLsizei,
175                            format: GLenum,
176                            pixel_type: GLenum) {
177        self.ffi_gl_.ReadPixels(x, y, width, height, format, pixel_type, ptr::null_mut());
178    }
179
180    fn sample_coverage(&self, value: GLclampf, invert: bool) {
181        unsafe {
182            self.ffi_gl_.SampleCoverage(value, invert as GLboolean);
183        }
184    }
185
186    fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
187        unsafe {
188            self.ffi_gl_.PolygonOffset(factor, units);
189        }
190    }
191
192    fn pixel_store_i(&self, name: GLenum, param: GLint) {
193        unsafe {
194            self.ffi_gl_.PixelStorei(name, param);
195        }
196    }
197
198    fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
199        let mut result = vec![0 as GLuint; n as usize];
200        unsafe {
201            self.ffi_gl_.GenBuffers(n, result.as_mut_ptr());
202        }
203        result
204    }
205
206    fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
207        let mut result = vec![0 as GLuint; n as usize];
208        unsafe {
209            self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr());
210        }
211        result
212    }
213
214    fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
215        let mut result = vec![0 as GLuint; n as usize];
216        unsafe {
217            self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr());
218        }
219        result
220    }
221
222    fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
223        let mut result = vec![0 as GLuint; n as usize];
224        unsafe {
225            self.ffi_gl_.GenTextures(n, result.as_mut_ptr());
226        }
227        result
228    }
229
230    fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
231        let mut result = vec![0 as GLuint; n as usize];
232        unsafe {
233            self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr())
234        }
235        result
236    }
237
238    fn gen_vertex_arrays_apple(&self, n: GLsizei) -> Vec<GLuint> {
239        let mut result = vec![0 as GLuint; n as usize];
240        unsafe {
241            self.ffi_gl_.GenVertexArraysAPPLE(n, result.as_mut_ptr())
242        }
243        result
244    }
245
246    fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
247        let mut result = vec![0 as GLuint; n as usize];
248        unsafe {
249            self.ffi_gl_.GenQueries(n, result.as_mut_ptr());
250        }
251        result
252    }
253
254    fn begin_query(&self, target: GLenum, id: GLuint) {
255        unsafe {
256            self.ffi_gl_.BeginQuery(target, id);
257        }
258    }
259
260    fn end_query(&self, target: GLenum) {
261        unsafe {
262            self.ffi_gl_.EndQuery(target);
263        }
264    }
265
266    fn query_counter(&self, id: GLuint, target: GLenum) {
267        unsafe {
268            self.ffi_gl_.QueryCounter(id, target);
269        }
270    }
271
272    fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
273        let mut result = 0;
274        unsafe {
275            self.ffi_gl_.GetQueryObjectiv(id, pname, &mut result);
276        }
277        result
278    }
279
280    fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
281        let mut result = 0;
282        unsafe {
283            self.ffi_gl_.GetQueryObjectuiv(id, pname, &mut result);
284        }
285        result
286    }
287
288    fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
289        let mut result = 0;
290        unsafe {
291            self.ffi_gl_.GetQueryObjecti64v(id, pname, &mut result);
292        }
293        result
294    }
295
296    fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
297        let mut result = 0;
298        unsafe {
299            self.ffi_gl_.GetQueryObjectui64v(id, pname, &mut result);
300        }
301        result
302    }
303
304    fn delete_queries(&self, queries: &[GLuint]) {
305        unsafe {
306            self.ffi_gl_
307                .DeleteQueries(queries.len() as GLsizei, queries.as_ptr());
308        }
309    }
310
311    fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) {
312        unsafe {
313            self.ffi_gl_
314                .DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr());
315        }
316    }
317
318    fn delete_vertex_arrays_apple(&self, vertex_arrays: &[GLuint]) {
319        unsafe {
320            self.ffi_gl_
321                .DeleteVertexArraysAPPLE(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr());
322        }
323    }
324
325    fn delete_buffers(&self, buffers: &[GLuint]) {
326        unsafe {
327            self.ffi_gl_
328                .DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr());
329        }
330    }
331
332    fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) {
333        unsafe {
334            self.ffi_gl_
335                .DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr());
336        }
337    }
338
339    fn delete_framebuffers(&self, framebuffers: &[GLuint]) {
340        unsafe {
341            self.ffi_gl_
342                .DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr());
343        }
344    }
345
346    fn delete_textures(&self, textures: &[GLuint]) {
347        unsafe {
348            self.ffi_gl_
349                .DeleteTextures(textures.len() as GLsizei, textures.as_ptr());
350        }
351    }
352
353    fn framebuffer_renderbuffer(
354        &self,
355        target: GLenum,
356        attachment: GLenum,
357        renderbuffertarget: GLenum,
358        renderbuffer: GLuint,
359    ) {
360        unsafe {
361            self.ffi_gl_.FramebufferRenderbuffer(
362                target,
363                attachment,
364                renderbuffertarget,
365                renderbuffer,
366            );
367        }
368    }
369
370    fn renderbuffer_storage(
371        &self,
372        target: GLenum,
373        internalformat: GLenum,
374        width: GLsizei,
375        height: GLsizei,
376    ) {
377        unsafe {
378            self.ffi_gl_
379                .RenderbufferStorage(target, internalformat, width, height);
380        }
381    }
382
383    fn depth_func(&self, func: GLenum) {
384        unsafe {
385            self.ffi_gl_.DepthFunc(func);
386        }
387    }
388
389    fn active_texture(&self, texture: GLenum) {
390        unsafe {
391            self.ffi_gl_.ActiveTexture(texture);
392        }
393    }
394
395    fn attach_shader(&self, program: GLuint, shader: GLuint) {
396        unsafe {
397            self.ffi_gl_.AttachShader(program, shader);
398        }
399    }
400
401    fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
402        let c_string = CString::new(name).unwrap();
403        unsafe {
404            self.ffi_gl_
405                .BindAttribLocation(program, index, c_string.as_ptr())
406        }
407    }
408
409    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
410    unsafe fn get_uniform_iv(&self, program: GLuint, location: GLint, result: &mut [GLint]) {
411        assert!(!result.is_empty());
412        self.ffi_gl_
413            .GetUniformiv(program, location, result.as_mut_ptr());
414    }
415
416    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
417    unsafe fn get_uniform_fv(&self, program: GLuint, location: GLint, result: &mut [GLfloat]) {
418        assert!(!result.is_empty());
419        self.ffi_gl_
420            .GetUniformfv(program, location, result.as_mut_ptr());
421    }
422
423    fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
424        let c_string = CString::new(name).unwrap();
425        unsafe {
426            self.ffi_gl_
427                .GetUniformBlockIndex(program, c_string.as_ptr())
428        }
429    }
430
431    fn get_uniform_indices(&self, program: GLuint, names: &[&str]) -> Vec<GLuint> {
432        let c_strings: Vec<CString> = names.iter().map(|n| CString::new(*n).unwrap()).collect();
433        let pointers: Vec<*const GLchar> = c_strings.iter().map(|string| string.as_ptr()).collect();
434        let mut result = Vec::with_capacity(c_strings.len());
435        unsafe {
436            result.set_len(c_strings.len());
437            self.ffi_gl_.GetUniformIndices(
438                program,
439                pointers.len() as GLsizei,
440                pointers.as_ptr(),
441                result.as_mut_ptr(),
442            );
443        }
444        result
445    }
446
447    fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
448        unsafe {
449            self.ffi_gl_.BindBufferBase(target, index, buffer);
450        }
451    }
452
453    fn bind_buffer_range(
454        &self,
455        target: GLenum,
456        index: GLuint,
457        buffer: GLuint,
458        offset: GLintptr,
459        size: GLsizeiptr,
460    ) {
461        unsafe {
462            self.ffi_gl_
463                .BindBufferRange(target, index, buffer, offset, size);
464        }
465    }
466
467    fn uniform_block_binding(
468        &self,
469        program: GLuint,
470        uniform_block_index: GLuint,
471        uniform_block_binding: GLuint,
472    ) {
473        unsafe {
474            self.ffi_gl_
475                .UniformBlockBinding(program, uniform_block_index, uniform_block_binding);
476        }
477    }
478
479    fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
480        unsafe {
481            self.ffi_gl_.BindBuffer(target, buffer);
482        }
483    }
484
485    fn bind_vertex_array(&self, vao: GLuint) {
486        unsafe {
487            self.ffi_gl_.BindVertexArray(vao);
488        }
489    }
490
491    fn bind_vertex_array_apple(&self, vao: GLuint) {
492        unsafe {
493            self.ffi_gl_.BindVertexArrayAPPLE(vao)
494        }
495    }
496
497    fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
498        unsafe {
499            self.ffi_gl_.BindRenderbuffer(target, renderbuffer);
500        }
501    }
502
503    fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
504        unsafe {
505            self.ffi_gl_.BindFramebuffer(target, framebuffer);
506        }
507    }
508
509    fn bind_texture(&self, target: GLenum, texture: GLuint) {
510        unsafe {
511            self.ffi_gl_.BindTexture(target, texture);
512        }
513    }
514
515    fn bind_vertex_buffer(&self, binding_index: GLuint, buffer: GLuint, offset: GLintptr, stride: GLint) {
516        unsafe { self.ffi_gl_.BindVertexBuffer(binding_index, buffer, offset, stride) }
517    }
518
519    fn draw_buffers(&self, bufs: &[GLenum]) {
520        unsafe {
521            self.ffi_gl_
522                .DrawBuffers(bufs.len() as GLsizei, bufs.as_ptr());
523        }
524    }
525
526    // FIXME: Does not verify buffer size -- unsafe!
527    fn tex_image_2d(
528        &self,
529        target: GLenum,
530        level: GLint,
531        internal_format: GLint,
532        width: GLsizei,
533        height: GLsizei,
534        border: GLint,
535        format: GLenum,
536        ty: GLenum,
537        opt_data: Option<&[u8]>,
538    ) {
539        match opt_data {
540            Some(data) => unsafe {
541                self.ffi_gl_.TexImage2D(
542                    target,
543                    level,
544                    internal_format,
545                    width,
546                    height,
547                    border,
548                    format,
549                    ty,
550                    data.as_ptr() as *const GLvoid,
551                );
552            },
553            None => unsafe {
554                self.ffi_gl_.TexImage2D(
555                    target,
556                    level,
557                    internal_format,
558                    width,
559                    height,
560                    border,
561                    format,
562                    ty,
563                    ptr::null(),
564                );
565            },
566        }
567    }
568
569    fn compressed_tex_image_2d(
570        &self,
571        target: GLenum,
572        level: GLint,
573        internal_format: GLenum,
574        width: GLsizei,
575        height: GLsizei,
576        border: GLint,
577        data: &[u8],
578    ) {
579        unsafe {
580            self.ffi_gl_.CompressedTexImage2D(
581                target,
582                level,
583                internal_format,
584                width,
585                height,
586                border,
587                data.len() as GLsizei,
588                data.as_ptr() as *const GLvoid,
589            );
590        }
591    }
592
593    fn compressed_tex_sub_image_2d(
594        &self,
595        target: GLenum,
596        level: GLint,
597        xoffset: GLint,
598        yoffset: GLint,
599        width: GLsizei,
600        height: GLsizei,
601        format: GLenum,
602        data: &[u8],
603    ) {
604        unsafe {
605            self.ffi_gl_.CompressedTexSubImage2D(
606                target,
607                level,
608                xoffset,
609                yoffset,
610                width,
611                height,
612                format,
613                data.len() as GLsizei,
614                data.as_ptr() as *const GLvoid,
615            );
616        }
617    }
618
619    // FIXME: Does not verify buffer size -- unsafe!
620    fn tex_image_3d(
621        &self,
622        target: GLenum,
623        level: GLint,
624        internal_format: GLint,
625        width: GLsizei,
626        height: GLsizei,
627        depth: GLsizei,
628        border: GLint,
629        format: GLenum,
630        ty: GLenum,
631        opt_data: Option<&[u8]>,
632    ) {
633        unsafe {
634            let pdata = match opt_data {
635                Some(data) => mem::transmute(data.as_ptr()),
636                None => ptr::null(),
637            };
638            self.ffi_gl_.TexImage3D(
639                target,
640                level,
641                internal_format,
642                width,
643                height,
644                depth,
645                border,
646                format,
647                ty,
648                pdata,
649            );
650        }
651    }
652
653    fn copy_tex_image_2d(
654        &self,
655        target: GLenum,
656        level: GLint,
657        internal_format: GLenum,
658        x: GLint,
659        y: GLint,
660        width: GLsizei,
661        height: GLsizei,
662        border: GLint,
663    ) {
664        unsafe {
665            self.ffi_gl_.CopyTexImage2D(
666                target,
667                level,
668                internal_format,
669                x,
670                y,
671                width,
672                height,
673                border,
674            );
675        }
676    }
677
678    fn copy_tex_sub_image_2d(
679        &self,
680        target: GLenum,
681        level: GLint,
682        xoffset: GLint,
683        yoffset: GLint,
684        x: GLint,
685        y: GLint,
686        width: GLsizei,
687        height: GLsizei,
688    ) {
689        unsafe {
690            self.ffi_gl_
691                .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
692        }
693    }
694
695    fn copy_tex_sub_image_3d(
696        &self,
697        target: GLenum,
698        level: GLint,
699        xoffset: GLint,
700        yoffset: GLint,
701        zoffset: GLint,
702        x: GLint,
703        y: GLint,
704        width: GLsizei,
705        height: GLsizei,
706    ) {
707        unsafe {
708            self.ffi_gl_.CopyTexSubImage3D(
709                target, level, xoffset, yoffset, zoffset, x, y, width, height,
710            );
711        }
712    }
713
714    fn tex_sub_image_2d(
715        &self,
716        target: GLenum,
717        level: GLint,
718        xoffset: GLint,
719        yoffset: GLint,
720        width: GLsizei,
721        height: GLsizei,
722        format: GLenum,
723        ty: GLenum,
724        data: &[u8],
725    ) {
726        unsafe {
727            self.ffi_gl_.TexSubImage2D(
728                target,
729                level,
730                xoffset,
731                yoffset,
732                width,
733                height,
734                format,
735                ty,
736                data.as_ptr() as *const c_void,
737            );
738        }
739    }
740
741    fn tex_sub_image_2d_pbo(
742        &self,
743        target: GLenum,
744        level: GLint,
745        xoffset: GLint,
746        yoffset: GLint,
747        width: GLsizei,
748        height: GLsizei,
749        format: GLenum,
750        ty: GLenum,
751        offset: usize,
752    ) {
753        unsafe {
754            self.ffi_gl_.TexSubImage2D(
755                target,
756                level,
757                xoffset,
758                yoffset,
759                width,
760                height,
761                format,
762                ty,
763                offset as *const c_void,
764            );
765        }
766    }
767
768    fn tex_sub_image_3d(
769        &self,
770        target: GLenum,
771        level: GLint,
772        xoffset: GLint,
773        yoffset: GLint,
774        zoffset: GLint,
775        width: GLsizei,
776        height: GLsizei,
777        depth: GLsizei,
778        format: GLenum,
779        ty: GLenum,
780        data: &[u8],
781    ) {
782        unsafe {
783            self.ffi_gl_.TexSubImage3D(
784                target,
785                level,
786                xoffset,
787                yoffset,
788                zoffset,
789                width,
790                height,
791                depth,
792                format,
793                ty,
794                data.as_ptr() as *const c_void,
795            );
796        }
797    }
798
799    fn tex_sub_image_3d_pbo(
800        &self,
801        target: GLenum,
802        level: GLint,
803        xoffset: GLint,
804        yoffset: GLint,
805        zoffset: GLint,
806        width: GLsizei,
807        height: GLsizei,
808        depth: GLsizei,
809        format: GLenum,
810        ty: GLenum,
811        offset: usize,
812    ) {
813        unsafe {
814            self.ffi_gl_.TexSubImage3D(
815                target,
816                level,
817                xoffset,
818                yoffset,
819                zoffset,
820                width,
821                height,
822                depth,
823                format,
824                ty,
825                offset as *const c_void,
826            );
827        }
828    }
829
830    fn tex_storage_2d(
831        &self,
832        target: GLenum,
833        levels: GLint,
834        internal_format: GLenum,
835        width: GLsizei,
836        height: GLsizei,
837    ) {
838        if self.ffi_gl_.TexStorage2D.is_loaded() {
839            unsafe {
840                self.ffi_gl_
841                    .TexStorage2D(target, levels, internal_format, width, height);
842            }
843        }
844    }
845
846    fn tex_storage_3d(
847        &self,
848        target: GLenum,
849        levels: GLint,
850        internal_format: GLenum,
851        width: GLsizei,
852        height: GLsizei,
853        depth: GLsizei,
854    ) {
855        if self.ffi_gl_.TexStorage3D.is_loaded() {
856            unsafe {
857                self.ffi_gl_
858                    .TexStorage3D(target, levels, internal_format, width, height, depth);
859            }
860        }
861    }
862
863    fn get_tex_image_into_buffer(
864        &self,
865        target: GLenum,
866        level: GLint,
867        format: GLenum,
868        ty: GLenum,
869        output: &mut [u8],
870    ) {
871        unsafe {
872            self.ffi_gl_
873                .GetTexImage(target, level, format, ty, output.as_mut_ptr() as *mut _);
874        }
875    }
876
877    unsafe fn copy_image_sub_data(
878        &self,
879        src_name: GLuint,
880        src_target: GLenum,
881        src_level: GLint,
882        src_x: GLint,
883        src_y: GLint,
884        src_z: GLint,
885        dst_name: GLuint,
886        dst_target: GLenum,
887        dst_level: GLint,
888        dst_x: GLint,
889        dst_y: GLint,
890        dst_z: GLint,
891        src_width: GLsizei,
892        src_height: GLsizei,
893        src_depth: GLsizei,
894    ) {
895        self.ffi_gl_.CopyImageSubData(
896            src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target, dst_level,
897            dst_x, dst_y, dst_z, src_width, src_height, src_depth,
898        );
899    }
900
901    fn invalidate_framebuffer(&self, target: GLenum, attachments: &[GLenum]) {
902        if self.ffi_gl_.InvalidateFramebuffer.is_loaded() {
903            unsafe {
904                self.ffi_gl_.InvalidateFramebuffer(
905                    target,
906                    attachments.len() as GLsizei,
907                    attachments.as_ptr(),
908                );
909            }
910        }
911    }
912
913    fn invalidate_sub_framebuffer(
914        &self,
915        target: GLenum,
916        attachments: &[GLenum],
917        xoffset: GLint,
918        yoffset: GLint,
919        width: GLsizei,
920        height: GLsizei,
921    ) {
922        if self.ffi_gl_.InvalidateSubFramebuffer.is_loaded() {
923            unsafe {
924                self.ffi_gl_.InvalidateSubFramebuffer(
925                    target,
926                    attachments.len() as GLsizei,
927                    attachments.as_ptr(),
928                    xoffset,
929                    yoffset,
930                    width,
931                    height,
932                );
933            }
934        }
935    }
936
937    #[inline]
938    unsafe fn get_integer_v(&self, name: GLenum, result: &mut [GLint]) {
939        assert!(!result.is_empty());
940        self.ffi_gl_.GetIntegerv(name, result.as_mut_ptr());
941    }
942
943    #[inline]
944    unsafe fn get_integer_64v(&self, name: GLenum, result: &mut [GLint64]) {
945        assert!(!result.is_empty());
946        self.ffi_gl_.GetInteger64v(name, result.as_mut_ptr());
947    }
948
949    #[inline]
950    unsafe fn get_integer_iv(&self, name: GLenum, index: GLuint, result: &mut [GLint]) {
951        assert!(!result.is_empty());
952        self.ffi_gl_.GetIntegeri_v(name, index, result.as_mut_ptr());
953    }
954
955    #[inline]
956    unsafe fn get_integer_64iv(&self, name: GLenum, index: GLuint, result: &mut [GLint64]) {
957        assert!(!result.is_empty());
958        self.ffi_gl_
959            .GetInteger64i_v(name, index, result.as_mut_ptr());
960    }
961
962    #[inline]
963    unsafe fn get_boolean_v(&self, name: GLenum, result: &mut [GLboolean]) {
964        assert!(!result.is_empty());
965        self.ffi_gl_.GetBooleanv(name, result.as_mut_ptr());
966    }
967
968    #[inline]
969    unsafe fn get_float_v(&self, name: GLenum, result: &mut [GLfloat]) {
970        assert!(!result.is_empty());
971        self.ffi_gl_.GetFloatv(name, result.as_mut_ptr());
972    }
973
974    fn get_framebuffer_attachment_parameter_iv(
975        &self,
976        target: GLenum,
977        attachment: GLenum,
978        pname: GLenum,
979    ) -> GLint {
980        let mut result: GLint = 0;
981        unsafe {
982            self.ffi_gl_.GetFramebufferAttachmentParameteriv(
983                target,
984                attachment,
985                pname,
986                &mut result,
987            );
988        }
989        result
990    }
991
992    fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
993        let mut result: GLint = 0;
994        unsafe {
995            self.ffi_gl_
996                .GetRenderbufferParameteriv(target, pname, &mut result);
997        }
998        result
999    }
1000
1001    fn get_tex_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
1002        let mut result: GLint = 0;
1003        unsafe {
1004            self.ffi_gl_.GetTexParameteriv(target, pname, &mut result);
1005        }
1006        result
1007    }
1008
1009    fn get_tex_parameter_fv(&self, target: GLenum, pname: GLenum) -> GLfloat {
1010        let mut result: GLfloat = 0.0;
1011        unsafe {
1012            self.ffi_gl_.GetTexParameterfv(target, pname, &mut result);
1013        }
1014        result
1015    }
1016
1017    fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
1018        unsafe {
1019            self.ffi_gl_.TexParameteri(target, pname, param);
1020        }
1021    }
1022
1023    fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
1024        unsafe {
1025            self.ffi_gl_.TexParameterf(target, pname, param);
1026        }
1027    }
1028
1029    fn framebuffer_texture_2d(
1030        &self,
1031        target: GLenum,
1032        attachment: GLenum,
1033        textarget: GLenum,
1034        texture: GLuint,
1035        level: GLint,
1036    ) {
1037        unsafe {
1038            self.ffi_gl_
1039                .FramebufferTexture2D(target, attachment, textarget, texture, level);
1040        }
1041    }
1042
1043    fn framebuffer_texture_layer(
1044        &self,
1045        target: GLenum,
1046        attachment: GLenum,
1047        texture: GLuint,
1048        level: GLint,
1049        layer: GLint,
1050    ) {
1051        unsafe {
1052            self.ffi_gl_
1053                .FramebufferTextureLayer(target, attachment, texture, level, layer);
1054        }
1055    }
1056
1057    fn blit_framebuffer(
1058        &self,
1059        src_x0: GLint,
1060        src_y0: GLint,
1061        src_x1: GLint,
1062        src_y1: GLint,
1063        dst_x0: GLint,
1064        dst_y0: GLint,
1065        dst_x1: GLint,
1066        dst_y1: GLint,
1067        mask: GLbitfield,
1068        filter: GLenum,
1069    ) {
1070        unsafe {
1071            self.ffi_gl_.BlitFramebuffer(
1072                src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
1073            );
1074        }
1075    }
1076
1077    fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
1078        unsafe { self.ffi_gl_.VertexAttrib4f(index, x, y, z, w) }
1079    }
1080
1081    fn vertex_attrib_binding(&self, attrib_index: GLuint, binding_index: GLuint) {
1082        unsafe { self.ffi_gl_.VertexAttribBinding(attrib_index, binding_index) }
1083    }
1084
1085    fn vertex_attrib_pointer_f32(
1086        &self,
1087        index: GLuint,
1088        size: GLint,
1089        normalized: bool,
1090        stride: GLsizei,
1091        offset: GLuint,
1092    ) {
1093        unsafe {
1094            self.ffi_gl_.VertexAttribPointer(
1095                index,
1096                size,
1097                ffi::FLOAT,
1098                normalized as GLboolean,
1099                stride,
1100                offset as *const GLvoid,
1101            )
1102        }
1103    }
1104
1105    fn vertex_attrib_pointer(
1106        &self,
1107        index: GLuint,
1108        size: GLint,
1109        type_: GLenum,
1110        normalized: bool,
1111        stride: GLsizei,
1112        offset: GLuint,
1113    ) {
1114        unsafe {
1115            self.ffi_gl_.VertexAttribPointer(
1116                index,
1117                size,
1118                type_,
1119                normalized as GLboolean,
1120                stride,
1121                offset as *const GLvoid,
1122            )
1123        }
1124    }
1125
1126    fn vertex_attrib_i_pointer(
1127        &self,
1128        index: GLuint,
1129        size: GLint,
1130        type_: GLenum,
1131        stride: GLsizei,
1132        offset: GLuint,
1133    ) {
1134        unsafe {
1135            self.ffi_gl_
1136                .VertexAttribIPointer(index, size, type_, stride, offset as *const GLvoid)
1137        }
1138    }
1139
1140    fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
1141        unsafe { self.ffi_gl_.VertexAttribDivisor(index, divisor) }
1142    }
1143
1144    fn vertex_attrib_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, normalized: bool, relative_offset: GLuint) {
1145        unsafe { self.ffi_gl_.VertexAttribFormat(attrib_index, size, type_, normalized as GLboolean, relative_offset) }
1146    }
1147
1148    fn vertex_attrib_i_format(&self, attrib_index: GLuint, size: GLint, type_: GLenum, relative_offset: GLuint) {
1149        unsafe { self.ffi_gl_.VertexAttribIFormat(attrib_index, size, type_, relative_offset) }
1150    }
1151
1152    fn vertex_binding_divisor(&self, binding_index: GLuint, divisor: GLuint) {
1153        unsafe { self.ffi_gl_.VertexBindingDivisor(binding_index, divisor) }
1154    }
1155
1156    fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
1157        unsafe {
1158            self.ffi_gl_.Viewport(x, y, width, height);
1159        }
1160    }
1161
1162    fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
1163        unsafe {
1164            self.ffi_gl_.Scissor(x, y, width, height);
1165        }
1166    }
1167
1168    fn line_width(&self, width: GLfloat) {
1169        unsafe {
1170            self.ffi_gl_.LineWidth(width);
1171        }
1172    }
1173
1174    fn use_program(&self, program: GLuint) {
1175        unsafe {
1176            self.ffi_gl_.UseProgram(program);
1177        }
1178    }
1179
1180    fn validate_program(&self, program: GLuint) {
1181        unsafe {
1182            self.ffi_gl_.ValidateProgram(program);
1183        }
1184    }
1185
1186    fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
1187        unsafe {
1188            return self.ffi_gl_.DrawArrays(mode, first, count);
1189        }
1190    }
1191
1192    fn draw_arrays_instanced(
1193        &self,
1194        mode: GLenum,
1195        first: GLint,
1196        count: GLsizei,
1197        primcount: GLsizei,
1198    ) {
1199        unsafe {
1200            return self
1201                .ffi_gl_
1202                .DrawArraysInstanced(mode, first, count, primcount);
1203        }
1204    }
1205
1206    fn draw_elements(
1207        &self,
1208        mode: GLenum,
1209        count: GLsizei,
1210        element_type: GLenum,
1211        indices_offset: GLuint,
1212    ) {
1213        unsafe {
1214            return self.ffi_gl_.DrawElements(
1215                mode,
1216                count,
1217                element_type,
1218                indices_offset as *const c_void,
1219            );
1220        }
1221    }
1222
1223    fn draw_elements_instanced(
1224        &self,
1225        mode: GLenum,
1226        count: GLsizei,
1227        element_type: GLenum,
1228        indices_offset: GLuint,
1229        primcount: GLsizei,
1230    ) {
1231        unsafe {
1232            return self.ffi_gl_.DrawElementsInstanced(
1233                mode,
1234                count,
1235                element_type,
1236                indices_offset as *const c_void,
1237                primcount,
1238            );
1239        }
1240    }
1241
1242    fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
1243        unsafe {
1244            self.ffi_gl_.BlendColor(r, g, b, a);
1245        }
1246    }
1247
1248    fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
1249        unsafe {
1250            self.ffi_gl_.BlendFunc(sfactor, dfactor);
1251        }
1252    }
1253
1254    fn blend_func_separate(
1255        &self,
1256        src_rgb: GLenum,
1257        dest_rgb: GLenum,
1258        src_alpha: GLenum,
1259        dest_alpha: GLenum,
1260    ) {
1261        unsafe {
1262            self.ffi_gl_
1263                .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha);
1264        }
1265    }
1266
1267    fn blend_equation(&self, mode: GLenum) {
1268        unsafe {
1269            self.ffi_gl_.BlendEquation(mode);
1270        }
1271    }
1272
1273    fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
1274        unsafe {
1275            self.ffi_gl_.BlendEquationSeparate(mode_rgb, mode_alpha);
1276        }
1277    }
1278
1279    fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
1280        unsafe {
1281            self.ffi_gl_.ColorMask(
1282                r as GLboolean,
1283                g as GLboolean,
1284                b as GLboolean,
1285                a as GLboolean,
1286            );
1287        }
1288    }
1289
1290    fn cull_face(&self, mode: GLenum) {
1291        unsafe {
1292            self.ffi_gl_.CullFace(mode);
1293        }
1294    }
1295
1296    fn front_face(&self, mode: GLenum) {
1297        unsafe {
1298            self.ffi_gl_.FrontFace(mode);
1299        }
1300    }
1301
1302    fn enable(&self, cap: GLenum) {
1303        unsafe {
1304            self.ffi_gl_.Enable(cap);
1305        }
1306    }
1307
1308    fn disable(&self, cap: GLenum) {
1309        unsafe {
1310            self.ffi_gl_.Disable(cap);
1311        }
1312    }
1313
1314    fn hint(&self, param_name: GLenum, param_val: GLenum) {
1315        unsafe {
1316            self.ffi_gl_.Hint(param_name, param_val);
1317        }
1318    }
1319
1320    fn is_enabled(&self, cap: GLenum) -> GLboolean {
1321        unsafe { self.ffi_gl_.IsEnabled(cap) }
1322    }
1323
1324    fn is_shader(&self, shader: GLuint) -> GLboolean {
1325        unsafe { self.ffi_gl_.IsShader(shader) }
1326    }
1327
1328    fn is_texture(&self, texture: GLenum) -> GLboolean {
1329        unsafe { self.ffi_gl_.IsTexture(texture) }
1330    }
1331
1332    fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
1333        unsafe { self.ffi_gl_.IsFramebuffer(framebuffer) }
1334    }
1335
1336    fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
1337        unsafe { self.ffi_gl_.IsRenderbuffer(renderbuffer) }
1338    }
1339
1340    fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
1341        unsafe { self.ffi_gl_.CheckFramebufferStatus(target) }
1342    }
1343
1344    fn enable_vertex_attrib_array(&self, index: GLuint) {
1345        unsafe {
1346            self.ffi_gl_.EnableVertexAttribArray(index);
1347        }
1348    }
1349
1350    fn disable_vertex_attrib_array(&self, index: GLuint) {
1351        unsafe {
1352            self.ffi_gl_.DisableVertexAttribArray(index);
1353        }
1354    }
1355
1356    fn uniform_1f(&self, location: GLint, v0: GLfloat) {
1357        unsafe {
1358            self.ffi_gl_.Uniform1f(location, v0);
1359        }
1360    }
1361
1362    fn uniform_1fv(&self, location: GLint, values: &[f32]) {
1363        unsafe {
1364            self.ffi_gl_
1365                .Uniform1fv(location, values.len() as GLsizei, values.as_ptr());
1366        }
1367    }
1368
1369    fn uniform_1i(&self, location: GLint, v0: GLint) {
1370        unsafe {
1371            self.ffi_gl_.Uniform1i(location, v0);
1372        }
1373    }
1374
1375    fn uniform_1iv(&self, location: GLint, values: &[i32]) {
1376        unsafe {
1377            self.ffi_gl_
1378                .Uniform1iv(location, values.len() as GLsizei, values.as_ptr());
1379        }
1380    }
1381
1382    fn uniform_1ui(&self, location: GLint, v0: GLuint) {
1383        unsafe {
1384            self.ffi_gl_.Uniform1ui(location, v0);
1385        }
1386    }
1387
1388    fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
1389        unsafe {
1390            self.ffi_gl_.Uniform2f(location, v0, v1);
1391        }
1392    }
1393
1394    fn uniform_2fv(&self, location: GLint, values: &[f32]) {
1395        unsafe {
1396            self.ffi_gl_
1397                .Uniform2fv(location, (values.len() / 2) as GLsizei, values.as_ptr());
1398        }
1399    }
1400
1401    fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
1402        unsafe {
1403            self.ffi_gl_.Uniform2i(location, v0, v1);
1404        }
1405    }
1406
1407    fn uniform_2iv(&self, location: GLint, values: &[i32]) {
1408        unsafe {
1409            self.ffi_gl_
1410                .Uniform2iv(location, (values.len() / 2) as GLsizei, values.as_ptr());
1411        }
1412    }
1413
1414    fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
1415        unsafe {
1416            self.ffi_gl_.Uniform2ui(location, v0, v1);
1417        }
1418    }
1419
1420    fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
1421        unsafe {
1422            self.ffi_gl_.Uniform3f(location, v0, v1, v2);
1423        }
1424    }
1425
1426    fn uniform_3fv(&self, location: GLint, values: &[f32]) {
1427        unsafe {
1428            self.ffi_gl_
1429                .Uniform3fv(location, (values.len() / 3) as GLsizei, values.as_ptr());
1430        }
1431    }
1432
1433    fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
1434        unsafe {
1435            self.ffi_gl_.Uniform3i(location, v0, v1, v2);
1436        }
1437    }
1438
1439    fn uniform_3iv(&self, location: GLint, values: &[i32]) {
1440        unsafe {
1441            self.ffi_gl_
1442                .Uniform3iv(location, (values.len() / 3) as GLsizei, values.as_ptr());
1443        }
1444    }
1445
1446    fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
1447        unsafe {
1448            self.ffi_gl_.Uniform3ui(location, v0, v1, v2);
1449        }
1450    }
1451
1452    fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
1453        unsafe {
1454            self.ffi_gl_.Uniform4f(location, x, y, z, w);
1455        }
1456    }
1457
1458    fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
1459        unsafe {
1460            self.ffi_gl_.Uniform4i(location, x, y, z, w);
1461        }
1462    }
1463
1464    fn uniform_4iv(&self, location: GLint, values: &[i32]) {
1465        unsafe {
1466            self.ffi_gl_
1467                .Uniform4iv(location, (values.len() / 4) as GLsizei, values.as_ptr());
1468        }
1469    }
1470
1471    fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
1472        unsafe {
1473            self.ffi_gl_.Uniform4ui(location, x, y, z, w);
1474        }
1475    }
1476
1477    fn uniform_4fv(&self, location: GLint, values: &[f32]) {
1478        unsafe {
1479            self.ffi_gl_
1480                .Uniform4fv(location, (values.len() / 4) as GLsizei, values.as_ptr());
1481        }
1482    }
1483
1484    fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) {
1485        unsafe {
1486            self.ffi_gl_.UniformMatrix2fv(
1487                location,
1488                (value.len() / 4) as GLsizei,
1489                transpose as GLboolean,
1490                value.as_ptr(),
1491            );
1492        }
1493    }
1494
1495    fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) {
1496        unsafe {
1497            self.ffi_gl_.UniformMatrix3fv(
1498                location,
1499                (value.len() / 9) as GLsizei,
1500                transpose as GLboolean,
1501                value.as_ptr(),
1502            );
1503        }
1504    }
1505
1506    fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) {
1507        unsafe {
1508            self.ffi_gl_.UniformMatrix4fv(
1509                location,
1510                (value.len() / 16) as GLsizei,
1511                transpose as GLboolean,
1512                value.as_ptr(),
1513            );
1514        }
1515    }
1516
1517    fn depth_mask(&self, flag: bool) {
1518        unsafe {
1519            self.ffi_gl_.DepthMask(flag as GLboolean);
1520        }
1521    }
1522
1523    fn depth_range(&self, near: f64, far: f64) {
1524        unsafe {
1525            self.ffi_gl_.DepthRange(near as GLclampd, far as GLclampd);
1526        }
1527    }
1528
1529    fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
1530        let mut buf_size = [0];
1531        unsafe {
1532            self.get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH, &mut buf_size);
1533        }
1534        let mut name = vec![0u8; buf_size[0] as usize];
1535        let mut length = 0 as GLsizei;
1536        let mut size = 0 as i32;
1537        let mut type_ = 0 as u32;
1538        unsafe {
1539            self.ffi_gl_.GetActiveAttrib(
1540                program,
1541                index,
1542                buf_size[0],
1543                &mut length,
1544                &mut size,
1545                &mut type_,
1546                name.as_mut_ptr() as *mut GLchar,
1547            );
1548        }
1549        name.truncate(if length > 0 { length as usize } else { 0 });
1550        (size, type_, String::from_utf8(name).unwrap())
1551    }
1552
1553    fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
1554        let mut buf_size = [0];
1555        unsafe {
1556            self.get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH, &mut buf_size);
1557        }
1558        let mut name = vec![0 as u8; buf_size[0] as usize];
1559        let mut length: GLsizei = 0;
1560        let mut size: i32 = 0;
1561        let mut type_: u32 = 0;
1562
1563        unsafe {
1564            self.ffi_gl_.GetActiveUniform(
1565                program,
1566                index,
1567                buf_size[0],
1568                &mut length,
1569                &mut size,
1570                &mut type_,
1571                name.as_mut_ptr() as *mut GLchar,
1572            );
1573        }
1574
1575        name.truncate(if length > 0 { length as usize } else { 0 });
1576
1577        (size, type_, String::from_utf8(name).unwrap())
1578    }
1579
1580    fn get_active_uniforms_iv(
1581        &self,
1582        program: GLuint,
1583        indices: Vec<GLuint>,
1584        pname: GLenum,
1585    ) -> Vec<GLint> {
1586        let mut result = Vec::with_capacity(indices.len());
1587        unsafe {
1588            result.set_len(indices.len());
1589            self.ffi_gl_.GetActiveUniformsiv(
1590                program,
1591                indices.len() as GLsizei,
1592                indices.as_ptr(),
1593                pname,
1594                result.as_mut_ptr(),
1595            );
1596        }
1597        result
1598    }
1599
1600    fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint {
1601        let mut result = 0;
1602        unsafe {
1603            self.ffi_gl_
1604                .GetActiveUniformBlockiv(program, index, pname, &mut result);
1605        }
1606        result
1607    }
1608
1609    fn get_active_uniform_block_iv(
1610        &self,
1611        program: GLuint,
1612        index: GLuint,
1613        pname: GLenum,
1614    ) -> Vec<GLint> {
1615        let count =
1616            self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_ACTIVE_UNIFORMS);
1617        let mut result = Vec::with_capacity(count as usize);
1618        unsafe {
1619            result.set_len(count as usize);
1620            self.ffi_gl_
1621                .GetActiveUniformBlockiv(program, index, pname, result.as_mut_ptr());
1622        }
1623        result
1624    }
1625
1626    fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> String {
1627        let buf_size =
1628            self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_NAME_LENGTH);
1629        let mut name = vec![0 as u8; buf_size as usize];
1630        let mut length: GLsizei = 0;
1631        unsafe {
1632            self.ffi_gl_.GetActiveUniformBlockName(
1633                program,
1634                index,
1635                buf_size,
1636                &mut length,
1637                name.as_mut_ptr() as *mut GLchar,
1638            );
1639        }
1640        name.truncate(if length > 0 { length as usize } else { 0 });
1641
1642        String::from_utf8(name).unwrap()
1643    }
1644
1645    fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
1646        let name = CString::new(name).unwrap();
1647        unsafe { self.ffi_gl_.GetAttribLocation(program, name.as_ptr()) }
1648    }
1649
1650    fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
1651        let name = CString::new(name).unwrap();
1652        unsafe { self.ffi_gl_.GetFragDataLocation(program, name.as_ptr()) }
1653    }
1654
1655    fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
1656        let name = CString::new(name).unwrap();
1657        unsafe { self.ffi_gl_.GetUniformLocation(program, name.as_ptr()) }
1658    }
1659
1660    fn get_program_info_log(&self, program: GLuint) -> String {
1661        let mut max_len = [0];
1662        unsafe {
1663            self.get_program_iv(program, ffi::INFO_LOG_LENGTH, &mut max_len);
1664        }
1665        if max_len[0] == 0 {
1666            return String::new();
1667        }
1668        let mut result = vec![0u8; max_len[0] as usize];
1669        let mut result_len = 0 as GLsizei;
1670        unsafe {
1671            self.ffi_gl_.GetProgramInfoLog(
1672                program,
1673                max_len[0] as GLsizei,
1674                &mut result_len,
1675                result.as_mut_ptr() as *mut GLchar,
1676            );
1677        }
1678        result.truncate(if result_len > 0 {
1679            result_len as usize
1680        } else {
1681            0
1682        });
1683        String::from_utf8(result).unwrap()
1684    }
1685
1686    #[inline]
1687    unsafe fn get_program_iv(&self, program: GLuint, pname: GLenum, result: &mut [GLint]) {
1688        assert!(!result.is_empty());
1689        self.ffi_gl_
1690            .GetProgramiv(program, pname, result.as_mut_ptr());
1691    }
1692
1693    fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) {
1694        if !self.ffi_gl_.GetProgramBinary.is_loaded() {
1695            return (Vec::new(), NONE);
1696        }
1697        let mut len = [0];
1698        unsafe {
1699            self.get_program_iv(program, ffi::PROGRAM_BINARY_LENGTH, &mut len);
1700        }
1701        if len[0] <= 0 {
1702            return (Vec::new(), NONE);
1703        }
1704        let mut binary: Vec<u8> = Vec::with_capacity(len[0] as usize);
1705        let mut format = NONE;
1706        let mut out_len = 0;
1707        unsafe {
1708            binary.set_len(len[0] as usize);
1709            self.ffi_gl_.GetProgramBinary(
1710                program,
1711                len[0],
1712                &mut out_len as *mut GLsizei,
1713                &mut format,
1714                binary.as_mut_ptr() as *mut c_void,
1715            );
1716        }
1717        if len[0] != out_len {
1718            return (Vec::new(), NONE);
1719        }
1720
1721        (binary, format)
1722    }
1723
1724    fn program_binary(&self, program: GLuint, format: GLenum, binary: &[u8]) {
1725        if !self.ffi_gl_.ProgramBinary.is_loaded() {
1726            return;
1727        }
1728        unsafe {
1729            self.ffi_gl_.ProgramBinary(
1730                program,
1731                format,
1732                binary.as_ptr() as *const c_void,
1733                binary.len() as GLsizei,
1734            );
1735        }
1736    }
1737
1738    fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
1739        if !self.ffi_gl_.ProgramParameteri.is_loaded() {
1740            return;
1741        }
1742        unsafe {
1743            self.ffi_gl_.ProgramParameteri(program, pname, value);
1744        }
1745    }
1746
1747    #[inline]
1748    unsafe fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, result: &mut [GLint]) {
1749        assert!(!result.is_empty());
1750        self.ffi_gl_
1751            .GetVertexAttribiv(index, pname, result.as_mut_ptr());
1752    }
1753
1754    #[inline]
1755    unsafe fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, result: &mut [GLfloat]) {
1756        assert!(!result.is_empty());
1757        self.ffi_gl_
1758            .GetVertexAttribfv(index, pname, result.as_mut_ptr());
1759    }
1760
1761    fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
1762        let mut result = 0 as *mut GLvoid;
1763        unsafe {
1764            self.ffi_gl_
1765                .GetVertexAttribPointerv(index, pname, &mut result)
1766        }
1767        result as GLsizeiptr
1768    }
1769
1770    fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
1771        let mut result = 0 as GLint;
1772        unsafe {
1773            self.ffi_gl_
1774                .GetBufferParameteriv(target, pname, &mut result);
1775        }
1776        result
1777    }
1778
1779    fn get_shader_info_log(&self, shader: GLuint) -> String {
1780        let mut max_len = [0];
1781        unsafe {
1782            self.get_shader_iv(shader, ffi::INFO_LOG_LENGTH, &mut max_len);
1783        }
1784        if max_len[0] == 0 {
1785            return String::new();
1786        }
1787        let mut result = vec![0u8; max_len[0] as usize];
1788        let mut result_len = 0 as GLsizei;
1789        unsafe {
1790            self.ffi_gl_.GetShaderInfoLog(
1791                shader,
1792                max_len[0] as GLsizei,
1793                &mut result_len,
1794                result.as_mut_ptr() as *mut GLchar,
1795            );
1796        }
1797        result.truncate(if result_len > 0 {
1798            result_len as usize
1799        } else {
1800            0
1801        });
1802        String::from_utf8(result).unwrap()
1803    }
1804
1805    fn get_string(&self, which: GLenum) -> String {
1806        unsafe {
1807            let llstr = self.ffi_gl_.GetString(which);
1808            if !llstr.is_null() {
1809                return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes())
1810                    .to_string();
1811            } else {
1812                return "".to_string();
1813            }
1814        }
1815    }
1816
1817    fn get_string_i(&self, which: GLenum, index: GLuint) -> String {
1818        unsafe {
1819            let llstr = self.ffi_gl_.GetStringi(which, index);
1820            if !llstr.is_null() {
1821                str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes())
1822                    .to_string()
1823            } else {
1824                "".to_string()
1825            }
1826        }
1827    }
1828
1829    unsafe fn get_shader_iv(&self, shader: GLuint, pname: GLenum, result: &mut [GLint]) {
1830        assert!(!result.is_empty());
1831        self.ffi_gl_.GetShaderiv(shader, pname, result.as_mut_ptr());
1832    }
1833
1834    fn get_shader_precision_format(
1835        &self,
1836        _shader_type: GLuint,
1837        precision_type: GLuint,
1838    ) -> (GLint, GLint, GLint) {
1839        // gl.GetShaderPrecisionFormat is not available until OpenGL 4.1.
1840        // Fallback to OpenGL standard precissions that most desktop hardware support.
1841        match precision_type {
1842            ffi::LOW_FLOAT | ffi::MEDIUM_FLOAT | ffi::HIGH_FLOAT => {
1843                // Fallback to IEEE 754 single precision
1844                // Range: from -2^127 to 2^127
1845                // Significand precision: 23 bits
1846                (127, 127, 23)
1847            }
1848            ffi::LOW_INT | ffi::MEDIUM_INT | ffi::HIGH_INT => {
1849                // Fallback to single precision integer
1850                // Range: from -2^24 to 2^24
1851                // Precision: For integer formats this value is always 0
1852                (24, 24, 0)
1853            }
1854            _ => (0, 0, 0),
1855        }
1856    }
1857
1858    fn compile_shader(&self, shader: GLuint) {
1859        unsafe {
1860            self.ffi_gl_.CompileShader(shader);
1861        }
1862    }
1863
1864    fn create_program(&self) -> GLuint {
1865        unsafe {
1866            return self.ffi_gl_.CreateProgram();
1867        }
1868    }
1869
1870    fn delete_program(&self, program: GLuint) {
1871        unsafe {
1872            self.ffi_gl_.DeleteProgram(program);
1873        }
1874    }
1875
1876    fn create_shader(&self, shader_type: GLenum) -> GLuint {
1877        unsafe {
1878            return self.ffi_gl_.CreateShader(shader_type);
1879        }
1880    }
1881
1882    fn delete_shader(&self, shader: GLuint) {
1883        unsafe {
1884            self.ffi_gl_.DeleteShader(shader);
1885        }
1886    }
1887
1888    fn detach_shader(&self, program: GLuint, shader: GLuint) {
1889        unsafe {
1890            self.ffi_gl_.DetachShader(program, shader);
1891        }
1892    }
1893
1894    fn link_program(&self, program: GLuint) {
1895        unsafe {
1896            return self.ffi_gl_.LinkProgram(program);
1897        }
1898    }
1899
1900    fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
1901        unsafe {
1902            self.ffi_gl_.ClearColor(r, g, b, a);
1903        }
1904    }
1905
1906    fn clear(&self, buffer_mask: GLbitfield) {
1907        unsafe {
1908            self.ffi_gl_.Clear(buffer_mask);
1909        }
1910    }
1911
1912    fn clear_depth(&self, depth: f64) {
1913        unsafe {
1914            self.ffi_gl_.ClearDepth(depth as GLclampd);
1915        }
1916    }
1917
1918    fn clear_stencil(&self, s: GLint) {
1919        unsafe {
1920            self.ffi_gl_.ClearStencil(s);
1921        }
1922    }
1923
1924    fn flush(&self) {
1925        unsafe {
1926            self.ffi_gl_.Flush();
1927        }
1928    }
1929
1930    fn finish(&self) {
1931        unsafe {
1932            self.ffi_gl_.Finish();
1933        }
1934    }
1935
1936    fn get_error(&self) -> GLenum {
1937        unsafe { self.ffi_gl_.GetError() }
1938    }
1939
1940    fn stencil_mask(&self, mask: GLuint) {
1941        unsafe { self.ffi_gl_.StencilMask(mask) }
1942    }
1943
1944    fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
1945        unsafe { self.ffi_gl_.StencilMaskSeparate(face, mask) }
1946    }
1947
1948    fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) {
1949        unsafe { self.ffi_gl_.StencilFunc(func, ref_, mask) }
1950    }
1951
1952    fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) {
1953        unsafe { self.ffi_gl_.StencilFuncSeparate(face, func, ref_, mask) }
1954    }
1955
1956    fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
1957        unsafe { self.ffi_gl_.StencilOp(sfail, dpfail, dppass) }
1958    }
1959
1960    fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
1961        unsafe { self.ffi_gl_.StencilOpSeparate(face, sfail, dpfail, dppass) }
1962    }
1963
1964    #[allow(unused_variables)]
1965    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) {
1966        panic!("not supported")
1967    }
1968
1969    #[allow(unused_variables)]
1970    fn egl_image_target_renderbuffer_storage_oes(&self, target: GLenum, image: GLeglImageOES) {
1971        panic!("not supported")
1972    }
1973
1974    fn generate_mipmap(&self, target: GLenum) {
1975        unsafe { self.ffi_gl_.GenerateMipmap(target) }
1976    }
1977
1978    fn insert_event_marker_ext(&self, message: &str) {
1979        if self.ffi_gl_.InsertEventMarkerEXT.is_loaded() {
1980            unsafe {
1981                self.ffi_gl_
1982                    .InsertEventMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
1983            }
1984        }
1985    }
1986
1987    fn push_group_marker_ext(&self, message: &str) {
1988        if self.ffi_gl_.PushGroupMarkerEXT.is_loaded() {
1989            unsafe {
1990                self.ffi_gl_
1991                    .PushGroupMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
1992            }
1993        }
1994    }
1995
1996    fn pop_group_marker_ext(&self) {
1997        if self.ffi_gl_.PopGroupMarkerEXT.is_loaded() {
1998            unsafe {
1999                self.ffi_gl_.PopGroupMarkerEXT();
2000            }
2001        }
2002    }
2003
2004    fn debug_message_insert_khr(&self, source: GLenum, type_: GLenum, id: GLuint, severity: GLenum, message: &str) {
2005        if self.ffi_gl_.DebugMessageInsertKHR.is_loaded() {
2006            unsafe {
2007                self.ffi_gl_
2008                    .DebugMessageInsertKHR(source, type_, id, severity, message.len() as GLsizei, message.as_ptr() as *const _);
2009            }
2010        }
2011    }
2012
2013    fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) {
2014        if self.ffi_gl_.PushDebugGroupKHR.is_loaded() {
2015            unsafe {
2016                self.ffi_gl_
2017                    .PushDebugGroupKHR(source, id, message.len() as GLsizei, message.as_ptr() as *const _);
2018            }
2019        }
2020    }
2021
2022    fn pop_debug_group_khr(&self) {
2023        if self.ffi_gl_.PopDebugGroupKHR.is_loaded() {
2024            unsafe {
2025                self.ffi_gl_.PopDebugGroupKHR();
2026            }
2027        }
2028    }
2029
2030    fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsync {
2031        unsafe { self.ffi_gl_.FenceSync(condition, flags) as *const _ }
2032    }
2033
2034    fn client_wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum {
2035        unsafe {
2036            self.ffi_gl_
2037                .ClientWaitSync(sync as *const _, flags, timeout)
2038        }
2039    }
2040
2041    fn wait_sync(&self, sync: GLsync, flags: GLbitfield, timeout: GLuint64) {
2042        unsafe {
2043            self.ffi_gl_.WaitSync(sync as *const _, flags, timeout);
2044        }
2045    }
2046
2047    fn texture_range_apple(&self, target: GLenum, data: &[u8]) {
2048        unsafe {
2049            self.ffi_gl_.TextureRangeAPPLE(
2050                target,
2051                data.len() as GLsizei,
2052                data.as_ptr() as *const c_void,
2053            );
2054        }
2055    }
2056
2057    fn delete_sync(&self, sync: GLsync) {
2058        unsafe {
2059            self.ffi_gl_.DeleteSync(sync as *const _);
2060        }
2061    }
2062
2063    fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint> {
2064        let mut result = vec![0 as GLuint; n as usize];
2065        unsafe {
2066            self.ffi_gl_.GenFencesAPPLE(n, result.as_mut_ptr());
2067        }
2068        result
2069    }
2070
2071    fn delete_fences_apple(&self, fences: &[GLuint]) {
2072        unsafe {
2073            self.ffi_gl_
2074                .DeleteFencesAPPLE(fences.len() as GLsizei, fences.as_ptr());
2075        }
2076    }
2077
2078    fn set_fence_apple(&self, fence: GLuint) {
2079        unsafe {
2080            self.ffi_gl_.SetFenceAPPLE(fence);
2081        }
2082    }
2083
2084    fn finish_fence_apple(&self, fence: GLuint) {
2085        unsafe {
2086            self.ffi_gl_.FinishFenceAPPLE(fence);
2087        }
2088    }
2089
2090    fn test_fence_apple(&self, fence: GLuint) {
2091        unsafe {
2092            self.ffi_gl_.TestFenceAPPLE(fence);
2093        }
2094    }
2095
2096    fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean {
2097        unsafe {
2098            self.ffi_gl_.TestObjectAPPLE(object, name)
2099        }
2100    }
2101
2102    fn finish_object_apple(&self, object: GLenum, name: GLuint) {
2103        unsafe {
2104            // the spec has a typo for name as GLint instead of GLuint
2105            self.ffi_gl_.FinishObjectAPPLE(object, name as GLint);
2106        }
2107    }
2108
2109    // GL_ARB_blend_func_extended
2110    fn bind_frag_data_location_indexed(
2111        &self,
2112        program: GLuint,
2113        color_number: GLuint,
2114        index: GLuint,
2115        name: &str,
2116    ) {
2117        if !self.ffi_gl_.BindFragDataLocationIndexed.is_loaded() {
2118            return;
2119        }
2120
2121        let c_string = CString::new(name).unwrap();
2122
2123        unsafe {
2124            self.ffi_gl_.BindFragDataLocationIndexed(
2125                program,
2126                color_number,
2127                index,
2128                c_string.as_ptr(),
2129            )
2130        }
2131    }
2132
2133    fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint {
2134        if !self.ffi_gl_.GetFragDataIndex.is_loaded() {
2135            return -1;
2136        }
2137
2138        let c_string = CString::new(name).unwrap();
2139
2140        unsafe { self.ffi_gl_.GetFragDataIndex(program, c_string.as_ptr()) }
2141    }
2142
2143    // GL_KHR_debug
2144    fn get_debug_messages(&self) -> Vec<DebugMessage> {
2145        if !self.ffi_gl_.GetDebugMessageLog.is_loaded() {
2146            return Vec::new();
2147        }
2148
2149        let mut max_message_len = 0;
2150        unsafe {
2151            self.ffi_gl_
2152                .GetIntegerv(ffi::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_len)
2153        }
2154
2155        let mut output = Vec::new();
2156        const CAPACITY: usize = 5;
2157
2158        let mut msg_data = vec![0u8; CAPACITY * max_message_len as usize];
2159        let mut sources = [0 as GLenum; CAPACITY];
2160        let mut types = [0 as GLenum; CAPACITY];
2161        let mut severities = [0 as GLenum; CAPACITY];
2162        let mut ids = [0 as GLuint; CAPACITY];
2163        let mut lengths = [0 as GLsizei; CAPACITY];
2164
2165        loop {
2166            let count = unsafe {
2167                // ANGLE can return one more message than the count argument specifies,
2168                // so we deliberately request one less than the capacity of our buffers.
2169                // https://issues.angleproject.org/issues/425579207
2170                self.ffi_gl_.GetDebugMessageLog(
2171                    (CAPACITY - 1) as _,
2172                    msg_data.len() as _,
2173                    sources.as_mut_ptr(),
2174                    types.as_mut_ptr(),
2175                    ids.as_mut_ptr(),
2176                    severities.as_mut_ptr(),
2177                    lengths.as_mut_ptr(),
2178                    msg_data.as_mut_ptr() as *mut _,
2179                )
2180            };
2181            let count = CAPACITY.min(count as usize);
2182
2183            let mut offset = 0;
2184            output.extend((0..count).map(|i| {
2185                let len = lengths[i] as usize;
2186                let slice = &msg_data[offset..offset + len];
2187                offset += len;
2188                DebugMessage {
2189                    message: String::from_utf8_lossy(slice).to_string(),
2190                    source: sources[i],
2191                    ty: types[i],
2192                    id: ids[i],
2193                    severity: severities[i],
2194                }
2195            }));
2196
2197            if (count as usize) < CAPACITY {
2198                return output;
2199            }
2200        }
2201    }
2202
2203    fn provoking_vertex_angle(&self, _mode: GLenum) {
2204        unimplemented!("This extension is GLES only");
2205    }
2206
2207    // GL_KHR_blend_equation_advanced
2208    fn blend_barrier_khr(&self) {
2209        if self.ffi_gl_.BlendBarrierKHR.is_loaded() {
2210            unsafe {
2211                self.ffi_gl_.BlendBarrierKHR();
2212            }
2213        }
2214    }
2215
2216    // GL_CHROMIUM_copy_texture
2217    fn copy_texture_chromium(&self,
2218        _source_id: GLuint, _source_level: GLint,
2219        _dest_target: GLenum, _dest_id: GLuint, _dest_level: GLint,
2220        _internal_format: GLint, _dest_type: GLenum,
2221        _unpack_flip_y: GLboolean, _unpack_premultiply_alpha: GLboolean, _unpack_unmultiply_alpha: GLboolean)
2222    {
2223        unimplemented!("This extension is GLES only");
2224    }
2225    fn copy_sub_texture_chromium(&self,
2226        _source_id: GLuint, _source_level: GLint,
2227        _dest_target: GLenum, _dest_id: GLuint, _dest_level: GLint,
2228        _x_offset: GLint, _y_offset: GLint, _x: GLint, _y: GLint, _width: GLsizei, _height: GLsizei,
2229        _unpack_flip_y: GLboolean, _unpack_premultiply_alpha: GLboolean, _unpack_unmultiply_alpha: GLboolean)
2230    {
2231        unimplemented!("This extension is GLES only");
2232    }
2233
2234    // GL_ANGLE_copy_texture_3d
2235    fn copy_texture_3d_angle(
2236        &self,
2237        _source_id: GLuint,
2238        _source_level: GLint,
2239        _dest_target: GLenum,
2240        _dest_id: GLuint,
2241        _dest_level: GLint,
2242        _internal_format: GLint,
2243        _dest_type: GLenum,
2244        _unpack_flip_y: GLboolean,
2245        _unpack_premultiply_alpha: GLboolean,
2246        _unpack_unmultiply_alpha: GLboolean,
2247    ) {
2248        unimplemented!("This extension is ANGLE only");
2249    }
2250
2251    fn copy_sub_texture_3d_angle(
2252        &self,
2253        _source_id: GLuint,
2254        _source_level: GLint,
2255        _dest_target: GLenum,
2256        _dest_id: GLuint,
2257        _dest_level: GLint,
2258        _x_offset: GLint,
2259        _y_offset: GLint,
2260        _z_offset: GLint,
2261        _x: GLint,
2262        _y: GLint,
2263        _z: GLint,
2264        _width: GLsizei,
2265        _height: GLsizei,
2266        _depth: GLsizei,
2267        _unpack_flip_y: GLboolean,
2268        _unpack_premultiply_alpha: GLboolean,
2269        _unpack_unmultiply_alpha: GLboolean,
2270    ) {
2271        unimplemented!("This extension is ANGLE only");
2272    }
2273
2274    fn buffer_storage(
2275        &self,
2276        target: GLenum,
2277        size: GLsizeiptr,
2278        data: *const GLvoid,
2279        flags: GLbitfield,
2280    ) {
2281        unsafe {
2282            self.ffi_gl_.BufferStorage(target, size, data, flags);
2283        }
2284    }
2285
2286    fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) {
2287        unsafe {
2288            self.ffi_gl_.FlushMappedBufferRange(target, offset, length);
2289        }
2290    }
2291
2292    fn start_tiling_qcom(&self, _x: GLuint, _y: GLuint, _width: GLuint, _height: GLuint, _preserve_mask: GLbitfield) {
2293    }
2294
2295    fn end_tiling_qcom(&self, _preserve_mask: GLbitfield) {
2296    }
2297}