aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_limits.rs
blob: 2363011751543a0f5a57d8bb491b32c0d8b3ae8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use canvas_traits::webgl::GLLimits;
use sparkle::gl;
use sparkle::gl::GLenum;
use sparkle::gl::Gl;

pub trait GLLimitsDetect {
    fn detect(gl: &Gl) -> Self;
}

impl GLLimitsDetect for GLLimits {
    fn detect(gl: &Gl) -> GLLimits {
        let max_vertex_attribs = gl.get_integer(gl::MAX_VERTEX_ATTRIBS);
        let max_tex_size = gl.get_integer(gl::MAX_TEXTURE_SIZE);
        let max_cube_map_tex_size = gl.get_integer(gl::MAX_CUBE_MAP_TEXTURE_SIZE);
        let max_combined_texture_image_units = gl.get_integer(gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS);
        let max_renderbuffer_size = gl.get_integer(gl::MAX_RENDERBUFFER_SIZE);
        let max_texture_image_units = gl.get_integer(gl::MAX_TEXTURE_IMAGE_UNITS);
        let max_vertex_texture_image_units = gl.get_integer(gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS);

        // TODO: better value for this?
        let max_client_wait_timeout_webgl = std::time::Duration::new(1, 0);

        // Based on:
        // https://searchfox.org/mozilla-central/rev/5a744713370ec47969595e369fd5125f123e6d24/dom/canvas/WebGLContextValidate.cpp#523-558
        let (max_fragment_uniform_vectors, max_varying_vectors, max_vertex_uniform_vectors);
        match gl.try_get_integer(gl::MAX_FRAGMENT_UNIFORM_VECTORS) {
            Some(max_vectors) => {
                max_fragment_uniform_vectors = max_vectors;
                max_varying_vectors = gl.get_integer(gl::MAX_VARYING_VECTORS);
                max_vertex_uniform_vectors = gl.get_integer(gl::MAX_VERTEX_UNIFORM_VECTORS);
            },
            None => {
                let max_fragment_uniform_components =
                    gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS);
                let max_vertex_uniform_components =
                    gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS);

                let max_vertex_output_components = gl
                    .try_get_integer(gl::MAX_VERTEX_OUTPUT_COMPONENTS)
                    .unwrap_or(0);
                let max_fragment_input_components = gl
                    .try_get_integer(gl::MAX_FRAGMENT_INPUT_COMPONENTS)
                    .unwrap_or(0);
                let max_varying_components = max_vertex_output_components
                    .min(max_fragment_input_components)
                    .max(16);

                max_fragment_uniform_vectors = max_fragment_uniform_components / 4;
                max_varying_vectors = max_varying_components / 4;
                max_vertex_uniform_vectors = max_vertex_uniform_components / 4;
            },
        }

        GLLimits {
            max_vertex_attribs,
            max_tex_size,
            max_cube_map_tex_size,
            max_combined_texture_image_units,
            max_fragment_uniform_vectors,
            max_renderbuffer_size,
            max_texture_image_units,
            max_varying_vectors,
            max_vertex_texture_image_units,
            max_vertex_uniform_vectors,
            max_client_wait_timeout_webgl,
        }
    }
}

trait GLExt {
    fn try_get_integer(self, parameter: GLenum) -> Option<u32>;
    fn get_integer(self, parameter: GLenum) -> u32;
}

impl<'a> GLExt for &'a Gl {
    #[allow(unsafe_code)]
    fn try_get_integer(self, parameter: GLenum) -> Option<u32> {
        let mut value = [0];
        unsafe {
            self.get_integer_v(parameter, &mut value);
        }
        if self.get_error() != gl::NO_ERROR {
            None
        } else {
            Some(value[0] as u32)
        }
    }

    fn get_integer(self, parameter: GLenum) -> u32 {
        self.try_get_integer(parameter).unwrap()
    }
}