mirror of
https://github.com/servo/servo.git
synced 2025-09-30 08:39:16 +01:00
script: Move WebGL DOM interfaces to script/dom/webgl/ (#38995)
Move interfaces defined by the WebGL spec to the `script/dom/webgl/ `module from `script/dom/`. `script/dom/webgl*.rs` -> `script/dom/webgl/` `script/dom/webgl_extensions` -> `script/dom/webgl/extensions` `script/dom/webgl_validations` -> `script/dom/webgl/validations` Testing: No changes, just a refactoring Fixes (partially): #38901 Signed-off-by: Andrei Volykhin <volykhin.andrei@huawei.com> Co-authored-by: Andrei Volykhin <volykhin.andrei@huawei.com>
This commit is contained in:
parent
6205c07114
commit
ef544a4db4
54 changed files with 162 additions and 148 deletions
|
@ -0,0 +1,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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::{
|
||||
ANGLEInstancedArraysConstants, ANGLEInstancedArraysMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct ANGLEInstancedArrays {
|
||||
reflector_: Reflector,
|
||||
ctx: Dom<WebGLRenderingContext>,
|
||||
}
|
||||
|
||||
impl ANGLEInstancedArrays {
|
||||
fn new_inherited(ctx: &WebGLRenderingContext) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
ctx: Dom::from_ref(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for ANGLEInstancedArrays {
|
||||
type Extension = Self;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(ANGLEInstancedArrays::new_inherited(ctx)),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&[
|
||||
"GL_ANGLE_instanced_arrays",
|
||||
"GL_ARB_instanced_arrays",
|
||||
"GL_EXT_instanced_arrays",
|
||||
"GL_NV_instanced_arrays",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_get_vertex_attrib_name(
|
||||
ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
|
||||
);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"ANGLE_instanced_arrays"
|
||||
}
|
||||
}
|
||||
|
||||
impl ANGLEInstancedArraysMethods<crate::DomTypeHolder> for ANGLEInstancedArrays {
|
||||
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
||||
fn DrawArraysInstancedANGLE(&self, mode: u32, first: i32, count: i32, primcount: i32) {
|
||||
handle_potential_webgl_error!(
|
||||
self.ctx,
|
||||
self.ctx
|
||||
.draw_arrays_instanced(mode, first, count, primcount)
|
||||
)
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
||||
fn DrawElementsInstancedANGLE(
|
||||
&self,
|
||||
mode: u32,
|
||||
count: i32,
|
||||
type_: u32,
|
||||
offset: i64,
|
||||
primcount: i32,
|
||||
) {
|
||||
handle_potential_webgl_error!(
|
||||
self.ctx,
|
||||
self.ctx
|
||||
.draw_elements_instanced(mode, count, type_, offset, primcount)
|
||||
)
|
||||
}
|
||||
|
||||
fn VertexAttribDivisorANGLE(&self, index: u32, divisor: u32) {
|
||||
self.ctx.vertex_attrib_divisor(index, divisor);
|
||||
}
|
||||
}
|
49
components/script/dom/webgl/extensions/ext/extblendminmax.rs
Normal file
49
components/script/dom/webgl/extensions/ext/extblendminmax.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct EXTBlendMinmax {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl EXTBlendMinmax {
|
||||
fn new_inherited() -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for EXTBlendMinmax {
|
||||
type Extension = Self;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited()), &*ctx.global(), can_gc)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_EXT_blend_minmax")
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_blend_minmax();
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"EXT_blend_minmax"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::extensions::oestexturehalffloat::OESTextureHalfFloat;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct EXTColorBufferHalfFloat {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl EXTColorBufferHalfFloat {
|
||||
fn new_inherited() -> EXTColorBufferHalfFloat {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for EXTColorBufferHalfFloat {
|
||||
type Extension = EXTColorBufferHalfFloat;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<EXTColorBufferHalfFloat> {
|
||||
reflect_dom_object(
|
||||
Box::new(EXTColorBufferHalfFloat::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
OESTextureHalfFloat::is_supported(ext)
|
||||
}
|
||||
|
||||
fn enable(_ext: &WebGLExtensions) {}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"EXT_color_buffer_half_float"
|
||||
}
|
||||
}
|
64
components/script/dom/webgl/extensions/ext/extfragdepth.rs
Normal file
64
components/script/dom/webgl/extensions/ext/extfragdepth.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* 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::{WebGLSLVersion, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct EXTFragDepth {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl EXTFragDepth {
|
||||
fn new_inherited() -> EXTFragDepth {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for EXTFragDepth {
|
||||
type Extension = Self;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited()), &*ctx.global(), can_gc)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
let min_glsl_version = if ext.is_gles() {
|
||||
WebGLSLVersion { major: 3, minor: 0 }
|
||||
} else {
|
||||
WebGLSLVersion {
|
||||
major: 1,
|
||||
minor: 10,
|
||||
}
|
||||
};
|
||||
match (
|
||||
ext.is_gles(),
|
||||
ext.is_min_glsl_version_satisfied(min_glsl_version),
|
||||
) {
|
||||
// ANGLE's shader translator can't translate ESSL1 exts to ESSL3. (bug
|
||||
// 1524804)
|
||||
(true, true) => false,
|
||||
(true, false) => ext.supports_gl_extension("GL_EXT_frag_depth"),
|
||||
(false, is_min_glsl_version_satisfied) => is_min_glsl_version_satisfied,
|
||||
}
|
||||
}
|
||||
|
||||
fn enable(_ext: &WebGLExtensions) {}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"EXT_frag_depth"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct EXTShaderTextureLod {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl EXTShaderTextureLod {
|
||||
fn new_inherited() -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for EXTShaderTextureLod {
|
||||
type Extension = Self;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited()), &*ctx.global(), can_gc)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
// This extension is always available on desktop GL.
|
||||
!ext.is_gles() || ext.supports_gl_extension("GL_EXT_shader_texture_lod")
|
||||
}
|
||||
|
||||
fn enable(_ext: &WebGLExtensions) {}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"EXT_shader_texture_lod"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct EXTTextureFilterAnisotropic {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl EXTTextureFilterAnisotropic {
|
||||
fn new_inherited() -> EXTTextureFilterAnisotropic {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for EXTTextureFilterAnisotropic {
|
||||
type Extension = EXTTextureFilterAnisotropic;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited()), &*ctx.global(), can_gc)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_EXT_texture_filter_anisotropic")
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_get_tex_parameter_name(
|
||||
EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
);
|
||||
ext.enable_get_parameter_name(
|
||||
EXTTextureFilterAnisotropicConstants::MAX_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"EXT_texture_filter_anisotropic"
|
||||
}
|
||||
}
|
23
components/script/dom/webgl/extensions/ext/mod.rs
Normal file
23
components/script/dom/webgl/extensions/ext/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* 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 super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
|
||||
pub(crate) mod angleinstancedarrays;
|
||||
pub(crate) mod extblendminmax;
|
||||
pub(crate) mod extcolorbufferhalffloat;
|
||||
pub(crate) mod extfragdepth;
|
||||
pub(crate) mod extshadertexturelod;
|
||||
pub(crate) mod exttexturefilteranisotropic;
|
||||
pub(crate) mod oeselementindexuint;
|
||||
pub(crate) mod oesstandardderivatives;
|
||||
pub(crate) mod oestexturefloat;
|
||||
pub(crate) mod oestexturefloatlinear;
|
||||
pub(crate) mod oestexturehalffloat;
|
||||
pub(crate) mod oestexturehalffloatlinear;
|
||||
pub(crate) mod oesvertexarrayobject;
|
||||
pub(crate) mod webglcolorbufferfloat;
|
||||
pub(crate) mod webglcompressedtextureetc1;
|
||||
pub(crate) mod webglcompressedtextures3tc;
|
|
@ -0,0 +1,54 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESElementIndexUint {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESElementIndexUint {
|
||||
fn new_inherited() -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESElementIndexUint {
|
||||
type Extension = Self;
|
||||
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESElementIndexUint::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
// This extension is always available in desktop OpenGL.
|
||||
!ext.is_gles() || ext.supports_gl_extension("GL_OES_element_index_uint")
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_element_index_uint();
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_element_index_uint"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::OESStandardDerivativesBinding::OESStandardDerivativesConstants;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESStandardDerivatives {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESStandardDerivatives {
|
||||
fn new_inherited() -> OESStandardDerivatives {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESStandardDerivatives {
|
||||
type Extension = OESStandardDerivatives;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESStandardDerivatives> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESStandardDerivatives::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
// The standard derivatives are always available in desktop OpenGL.
|
||||
!ext.is_gles() || ext.supports_any_gl_extension(&["GL_OES_standard_derivatives"])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_hint_target(
|
||||
OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES,
|
||||
);
|
||||
ext.enable_get_parameter_name(
|
||||
OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES,
|
||||
);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_standard_derivatives"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* 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::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions, constants as webgl};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESTextureFloat {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESTextureFloat {
|
||||
fn new_inherited() -> OESTextureFloat {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESTextureFloat {
|
||||
type Extension = OESTextureFloat;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESTextureFloat> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESTextureFloat::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&[
|
||||
"GL_OES_texture_float",
|
||||
"GL_ARB_texture_float",
|
||||
"GL_EXT_color_buffer_float",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_tex_type(webgl::FLOAT);
|
||||
ext.add_effective_tex_internal_format(TexFormat::RGBA, webgl::FLOAT, TexFormat::RGBA32f);
|
||||
ext.add_effective_tex_internal_format(TexFormat::RGB, webgl::FLOAT, TexFormat::RGB32f);
|
||||
ext.add_effective_tex_internal_format(
|
||||
TexFormat::Luminance,
|
||||
webgl::FLOAT,
|
||||
TexFormat::Luminance32f,
|
||||
);
|
||||
ext.add_effective_tex_internal_format(TexFormat::Alpha, webgl::FLOAT, TexFormat::Alpha32f);
|
||||
ext.add_effective_tex_internal_format(
|
||||
TexFormat::LuminanceAlpha,
|
||||
webgl::FLOAT,
|
||||
TexFormat::LuminanceAlpha32f,
|
||||
);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_texture_float"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions, constants as webgl};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESTextureFloatLinear {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESTextureFloatLinear {
|
||||
fn new_inherited() -> OESTextureFloatLinear {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESTextureFloatLinear {
|
||||
type Extension = OESTextureFloatLinear;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESTextureFloatLinear> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESTextureFloatLinear::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::All
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&["GL_OES_texture_float_linear", "GL_ARB_texture_float"])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_filterable_tex_type(webgl::FLOAT);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_texture_float_linear"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* 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::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESTextureHalfFloat {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESTextureHalfFloat {
|
||||
fn new_inherited() -> OESTextureHalfFloat {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESTextureHalfFloat {
|
||||
type Extension = OESTextureHalfFloat;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESTextureHalfFloat> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESTextureHalfFloat::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&[
|
||||
"GL_OES_texture_half_float",
|
||||
"GL_ARB_half_float_pixel",
|
||||
"GL_NV_half_float",
|
||||
"GL_EXT_color_buffer_half_float",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
let hf = OESTextureHalfFloatConstants::HALF_FLOAT_OES;
|
||||
ext.enable_tex_type(hf);
|
||||
ext.add_effective_tex_internal_format(TexFormat::RGBA, hf, TexFormat::RGBA16f);
|
||||
ext.add_effective_tex_internal_format(TexFormat::RGB, hf, TexFormat::RGB16f);
|
||||
ext.add_effective_tex_internal_format(TexFormat::Luminance, hf, TexFormat::Luminance16f);
|
||||
ext.add_effective_tex_internal_format(TexFormat::Alpha, hf, TexFormat::Alpha16f);
|
||||
ext.add_effective_tex_internal_format(
|
||||
TexFormat::LuminanceAlpha,
|
||||
hf,
|
||||
TexFormat::LuminanceAlpha16f,
|
||||
);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_texture_half_float"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESTextureHalfFloatLinear {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl OESTextureHalfFloatLinear {
|
||||
fn new_inherited() -> OESTextureHalfFloatLinear {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESTextureHalfFloatLinear {
|
||||
type Extension = OESTextureHalfFloatLinear;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESTextureHalfFloatLinear> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESTextureHalfFloatLinear::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::All
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&[
|
||||
"GL_OES_texture_float_linear",
|
||||
"GL_ARB_half_float_pixel",
|
||||
"GL_NV_half_float",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_filterable_tex_type(OESTextureHalfFloatConstants::HALF_FLOAT_OES);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_texture_half_float_linear"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::{
|
||||
OESVertexArrayObjectConstants, OESVertexArrayObjectMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct OESVertexArrayObject {
|
||||
reflector_: Reflector,
|
||||
ctx: Dom<WebGLRenderingContext>,
|
||||
}
|
||||
|
||||
impl OESVertexArrayObject {
|
||||
fn new_inherited(ctx: &WebGLRenderingContext) -> OESVertexArrayObject {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
ctx: Dom::from_ref(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OESVertexArrayObjectMethods<crate::DomTypeHolder> for OESVertexArrayObject {
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
|
||||
fn CreateVertexArrayOES(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> {
|
||||
self.ctx.create_vertex_array()
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
|
||||
fn DeleteVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
|
||||
self.ctx.delete_vertex_array(vao);
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
|
||||
fn IsVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
|
||||
self.ctx.is_vertex_array(vao)
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
|
||||
fn BindVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
|
||||
self.ctx.bind_vertex_array(vao);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for OESVertexArrayObject {
|
||||
type Extension = OESVertexArrayObject;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<OESVertexArrayObject> {
|
||||
reflect_dom_object(
|
||||
Box::new(OESVertexArrayObject::new_inherited(ctx)),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_any_gl_extension(&[
|
||||
"GL_OES_vertex_array_object",
|
||||
"GL_ARB_vertex_array_object",
|
||||
"GL_APPLE_vertex_array_object",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.enable_get_parameter_name(OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"OES_vertex_array_object"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* 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::WebGLVersion;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::extensions::oestexturefloat::OESTextureFloat;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WEBGLColorBufferFloat {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl WEBGLColorBufferFloat {
|
||||
fn new_inherited() -> WEBGLColorBufferFloat {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for WEBGLColorBufferFloat {
|
||||
type Extension = WEBGLColorBufferFloat;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<WEBGLColorBufferFloat> {
|
||||
reflect_dom_object(
|
||||
Box::new(WEBGLColorBufferFloat::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
OESTextureFloat::is_supported(ext)
|
||||
}
|
||||
|
||||
fn enable(_ext: &WebGLExtensions) {}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"WEBGL_color_buffer_float"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* 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::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WEBGLCompressedTextureETC1 {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl WEBGLCompressedTextureETC1 {
|
||||
fn new_inherited() -> WEBGLCompressedTextureETC1 {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for WEBGLCompressedTextureETC1 {
|
||||
type Extension = WEBGLCompressedTextureETC1;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<WEBGLCompressedTextureETC1> {
|
||||
reflect_dom_object(
|
||||
Box::new(WEBGLCompressedTextureETC1::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_OES_compressed_ETC1_RGB8_texture")
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.add_tex_compression_formats(&[TexCompression {
|
||||
format: TexFormat::CompressedRgbEtc1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::None,
|
||||
}]);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"WEBGL_compressed_texture_etc1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/* 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::{TexFormat, WebGLVersion};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webgltexture::{TexCompression, TexCompressionValidation};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WEBGLCompressedTextureS3TC {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl WEBGLCompressedTextureS3TC {
|
||||
fn new_inherited() -> WEBGLCompressedTextureS3TC {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExtension for WEBGLCompressedTextureS3TC {
|
||||
type Extension = WEBGLCompressedTextureS3TC;
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<WEBGLCompressedTextureS3TC> {
|
||||
reflect_dom_object(
|
||||
Box::new(WEBGLCompressedTextureS3TC::new_inherited()),
|
||||
&*ctx.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn spec() -> WebGLExtensionSpec {
|
||||
WebGLExtensionSpec::Specific(WebGLVersion::WebGL1)
|
||||
}
|
||||
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool {
|
||||
ext.supports_gl_extension("GL_EXT_texture_compression_s3tc") ||
|
||||
ext.supports_all_gl_extension(&[
|
||||
"GL_EXT_texture_compression_dxt1",
|
||||
"GL_ANGLE_texture_compression_dxt3",
|
||||
"GL_ANGLE_texture_compression_dxt5",
|
||||
])
|
||||
}
|
||||
|
||||
fn enable(ext: &WebGLExtensions) {
|
||||
ext.add_tex_compression_formats(&[
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbS3tcDxt1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt1,
|
||||
bytes_per_block: 8,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt3,
|
||||
bytes_per_block: 16,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
TexCompression {
|
||||
format: TexFormat::CompressedRgbaS3tcDxt5,
|
||||
bytes_per_block: 16,
|
||||
block_width: 4,
|
||||
block_height: 4,
|
||||
validation: TexCompressionValidation::S3TC,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"WEBGL_compressed_texture_s3tc"
|
||||
}
|
||||
}
|
43
components/script/dom/webgl/extensions/extension.rs
Normal file
43
components/script/dom/webgl/extensions/extension.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* 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::WebGLVersion;
|
||||
|
||||
use super::WebGLExtensions;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::trace::JSTraceable;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
/// Trait implemented by WebGL extensions.
|
||||
pub(crate) trait WebGLExtension: Sized
|
||||
where
|
||||
Self::Extension: DomObject + JSTraceable,
|
||||
{
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
type Extension;
|
||||
|
||||
/// Creates the DOM object of the WebGL extension.
|
||||
fn new(ctx: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self::Extension>;
|
||||
|
||||
/// Returns which WebGL spec is this extension written against.
|
||||
fn spec() -> WebGLExtensionSpec;
|
||||
|
||||
/// Checks if the extension is supported.
|
||||
fn is_supported(ext: &WebGLExtensions) -> bool;
|
||||
|
||||
/// Enable the extension.
|
||||
fn enable(ext: &WebGLExtensions);
|
||||
|
||||
/// Name of the WebGL Extension.
|
||||
fn name() -> &'static str;
|
||||
}
|
||||
|
||||
pub(crate) enum WebGLExtensionSpec {
|
||||
/// Extensions written against both WebGL and WebGL2 specs.
|
||||
All,
|
||||
/// Extensions writen against a specific WebGL version spec.
|
||||
Specific(WebGLVersion),
|
||||
}
|
476
components/script/dom/webgl/extensions/extensions.rs
Normal file
476
components/script/dom/webgl/extensions/extensions.rs
Normal file
|
@ -0,0 +1,476 @@
|
|||
/* 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 std::collections::HashMap;
|
||||
use std::iter::FromIterator;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use canvas_traits::webgl::{GlType, TexFormat, WebGLSLVersion, WebGLVersion};
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use js::jsapi::JSObject;
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
type GLenum = u32;
|
||||
|
||||
use super::wrapper::{TypedWebGLExtensionWrapper, WebGLExtensionWrapper};
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, ext};
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::OESStandardDerivativesBinding::OESStandardDerivativesConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use crate::dom::bindings::trace::JSTraceable;
|
||||
use crate::dom::webgl::extensions::extcolorbufferhalffloat::EXTColorBufferHalfFloat;
|
||||
use crate::dom::webgl::extensions::oestexturefloat::OESTextureFloat;
|
||||
use crate::dom::webgl::extensions::oestexturehalffloat::OESTextureHalfFloat;
|
||||
use crate::dom::webgl::extensions::webglcolorbufferfloat::WEBGLColorBufferFloat;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webgltexture::TexCompression;
|
||||
|
||||
// Data types that are implemented for texImage2D and texSubImage2D in a WebGL 1.0 context
|
||||
// but must trigger a InvalidValue error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float/
|
||||
const DEFAULT_DISABLED_TEX_TYPES_WEBGL1: [GLenum; 2] = [
|
||||
constants::FLOAT,
|
||||
OESTextureHalfFloatConstants::HALF_FLOAT_OES,
|
||||
];
|
||||
|
||||
// Data types that are implemented for textures in WebGLRenderingContext
|
||||
// but not allowed to use with linear filtering until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
|
||||
const DEFAULT_NOT_FILTERABLE_TEX_TYPES: [GLenum; 2] = [
|
||||
constants::FLOAT,
|
||||
OESTextureHalfFloatConstants::HALF_FLOAT_OES,
|
||||
];
|
||||
|
||||
// Param names that are implemented for glGetParameter in a WebGL 1.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
|
||||
const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1: [GLenum; 3] = [
|
||||
EXTTextureFilterAnisotropicConstants::MAX_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES,
|
||||
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES,
|
||||
];
|
||||
|
||||
// Param names that are implemented for glGetParameter in a WebGL 2.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
|
||||
const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::MAX_TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetTexParameter in a WebGL 1.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
|
||||
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetTexParameter in a WebGL 2.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
|
||||
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetVertexAttrib in a WebGL 1.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
||||
const DEFAULT_DISABLED_GET_VERTEX_ATTRIB_NAMES_WEBGL1: [GLenum; 1] =
|
||||
[ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE];
|
||||
|
||||
/// WebGL features that are enabled/disabled by WebGL Extensions.
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct WebGLExtensionFeatures {
|
||||
gl_extensions: FnvHashSet<String>,
|
||||
disabled_tex_types: FnvHashSet<GLenum>,
|
||||
not_filterable_tex_types: FnvHashSet<GLenum>,
|
||||
#[no_trace]
|
||||
effective_tex_internal_formats: FnvHashMap<TexFormatType, TexFormat>,
|
||||
/// WebGL Hint() targets enabled by extensions.
|
||||
hint_targets: FnvHashSet<GLenum>,
|
||||
/// WebGL GetParameter() names enabled by extensions.
|
||||
disabled_get_parameter_names: FnvHashSet<GLenum>,
|
||||
/// WebGL GetTexParameter() names enabled by extensions.
|
||||
disabled_get_tex_parameter_names: FnvHashSet<GLenum>,
|
||||
/// WebGL GetAttribVertex() names enabled by extensions.
|
||||
disabled_get_vertex_attrib_names: FnvHashSet<GLenum>,
|
||||
/// WebGL OES_element_index_uint extension.
|
||||
element_index_uint_enabled: bool,
|
||||
/// WebGL EXT_blend_minmax extension.
|
||||
blend_minmax_enabled: bool,
|
||||
/// WebGL supported texture compression formats enabled by extensions.
|
||||
tex_compression_formats: FnvHashMap<GLenum, TexCompression>,
|
||||
}
|
||||
|
||||
impl WebGLExtensionFeatures {
|
||||
fn new(webgl_version: WebGLVersion) -> Self {
|
||||
let (
|
||||
disabled_tex_types,
|
||||
disabled_get_parameter_names,
|
||||
disabled_get_tex_parameter_names,
|
||||
disabled_get_vertex_attrib_names,
|
||||
not_filterable_tex_types,
|
||||
element_index_uint_enabled,
|
||||
blend_minmax_enabled,
|
||||
) = match webgl_version {
|
||||
WebGLVersion::WebGL1 => (
|
||||
DEFAULT_DISABLED_TEX_TYPES_WEBGL1.iter().cloned().collect(),
|
||||
DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
DEFAULT_DISABLED_GET_VERTEX_ATTRIB_NAMES_WEBGL1
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
DEFAULT_NOT_FILTERABLE_TEX_TYPES.iter().cloned().collect(),
|
||||
false,
|
||||
false,
|
||||
),
|
||||
WebGLVersion::WebGL2 => (
|
||||
Default::default(),
|
||||
DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
true,
|
||||
true,
|
||||
),
|
||||
};
|
||||
Self {
|
||||
gl_extensions: Default::default(),
|
||||
disabled_tex_types,
|
||||
not_filterable_tex_types,
|
||||
effective_tex_internal_formats: Default::default(),
|
||||
hint_targets: Default::default(),
|
||||
disabled_get_parameter_names,
|
||||
disabled_get_tex_parameter_names,
|
||||
disabled_get_vertex_attrib_names,
|
||||
element_index_uint_enabled,
|
||||
blend_minmax_enabled,
|
||||
tex_compression_formats: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the list of implemented, supported and enabled WebGL extensions.
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
pub(crate) struct WebGLExtensions {
|
||||
extensions: DomRefCell<HashMap<String, Box<dyn WebGLExtensionWrapper>>>,
|
||||
features: DomRefCell<WebGLExtensionFeatures>,
|
||||
#[no_trace]
|
||||
webgl_version: WebGLVersion,
|
||||
#[no_trace]
|
||||
api_type: GlType,
|
||||
#[no_trace]
|
||||
glsl_version: WebGLSLVersion,
|
||||
}
|
||||
|
||||
impl WebGLExtensions {
|
||||
pub(crate) fn new(
|
||||
webgl_version: WebGLVersion,
|
||||
api_type: GlType,
|
||||
glsl_version: WebGLSLVersion,
|
||||
) -> WebGLExtensions {
|
||||
Self {
|
||||
extensions: DomRefCell::new(HashMap::new()),
|
||||
features: DomRefCell::new(WebGLExtensionFeatures::new(webgl_version)),
|
||||
webgl_version,
|
||||
api_type,
|
||||
glsl_version,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init_once<F>(&self, cb: F)
|
||||
where
|
||||
F: FnOnce() -> String,
|
||||
{
|
||||
if self.extensions.borrow().is_empty() {
|
||||
let gl_str = cb();
|
||||
self.features.borrow_mut().gl_extensions =
|
||||
FnvHashSet::from_iter(gl_str.split(&[',', ' '][..]).map(|s| s.into()));
|
||||
self.register_all_extensions();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn register<T: 'static + WebGLExtension + JSTraceable + MallocSizeOf>(&self) {
|
||||
let name = T::name().to_uppercase();
|
||||
self.extensions
|
||||
.borrow_mut()
|
||||
.insert(name, Box::new(TypedWebGLExtensionWrapper::<T>::new()));
|
||||
}
|
||||
|
||||
pub(crate) fn get_supported_extensions(&self) -> Vec<&'static str> {
|
||||
self.extensions
|
||||
.borrow()
|
||||
.iter()
|
||||
.filter(|v| {
|
||||
if let WebGLExtensionSpec::Specific(version) = v.1.spec() {
|
||||
if self.webgl_version != version {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
v.1.is_supported(self)
|
||||
})
|
||||
.map(|ref v| v.1.name())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn get_or_init_extension(
|
||||
&self,
|
||||
name: &str,
|
||||
ctx: &WebGLRenderingContext,
|
||||
) -> Option<NonNull<JSObject>> {
|
||||
let name = name.to_uppercase();
|
||||
self.extensions.borrow().get(&name).and_then(|extension| {
|
||||
if extension.is_supported(self) {
|
||||
Some(extension.instance_or_init(ctx, self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn is_enabled<T>(&self) -> bool
|
||||
where
|
||||
T: 'static + WebGLExtension + JSTraceable + MallocSizeOf,
|
||||
{
|
||||
let name = T::name().to_uppercase();
|
||||
self.extensions
|
||||
.borrow()
|
||||
.get(&name)
|
||||
.is_some_and(|ext| ext.is_enabled())
|
||||
}
|
||||
|
||||
pub(crate) fn supports_gl_extension(&self, name: &str) -> bool {
|
||||
self.features.borrow().gl_extensions.contains(name)
|
||||
}
|
||||
|
||||
pub(crate) fn supports_any_gl_extension(&self, names: &[&str]) -> bool {
|
||||
let features = self.features.borrow();
|
||||
names
|
||||
.iter()
|
||||
.any(|name| features.gl_extensions.contains(*name))
|
||||
}
|
||||
|
||||
pub(crate) fn supports_all_gl_extension(&self, names: &[&str]) -> bool {
|
||||
let features = self.features.borrow();
|
||||
names
|
||||
.iter()
|
||||
.all(|name| features.gl_extensions.contains(*name))
|
||||
}
|
||||
|
||||
pub(crate) fn enable_tex_type(&self, data_type: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.disabled_tex_types
|
||||
.remove(&data_type);
|
||||
}
|
||||
|
||||
pub(crate) fn is_tex_type_enabled(&self, data_type: GLenum) -> bool {
|
||||
!self
|
||||
.features
|
||||
.borrow()
|
||||
.disabled_tex_types
|
||||
.contains(&data_type)
|
||||
}
|
||||
|
||||
pub(crate) fn add_effective_tex_internal_format(
|
||||
&self,
|
||||
source_internal_format: TexFormat,
|
||||
source_data_type: u32,
|
||||
effective_internal_format: TexFormat,
|
||||
) {
|
||||
let format = TexFormatType(source_internal_format, source_data_type);
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.effective_tex_internal_formats
|
||||
.insert(format, effective_internal_format);
|
||||
}
|
||||
|
||||
pub(crate) fn get_effective_tex_internal_format(
|
||||
&self,
|
||||
source_internal_format: TexFormat,
|
||||
source_data_type: u32,
|
||||
) -> TexFormat {
|
||||
let format = TexFormatType(source_internal_format, source_data_type);
|
||||
*(self
|
||||
.features
|
||||
.borrow()
|
||||
.effective_tex_internal_formats
|
||||
.get(&format)
|
||||
.unwrap_or(&source_internal_format))
|
||||
}
|
||||
|
||||
pub(crate) fn enable_filterable_tex_type(&self, text_data_type: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.not_filterable_tex_types
|
||||
.remove(&text_data_type);
|
||||
}
|
||||
|
||||
pub(crate) fn is_filterable(&self, text_data_type: u32) -> bool {
|
||||
!self
|
||||
.features
|
||||
.borrow()
|
||||
.not_filterable_tex_types
|
||||
.contains(&text_data_type)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_hint_target(&self, name: GLenum) {
|
||||
self.features.borrow_mut().hint_targets.insert(name);
|
||||
}
|
||||
|
||||
pub(crate) fn is_hint_target_enabled(&self, name: GLenum) -> bool {
|
||||
self.features.borrow().hint_targets.contains(&name)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_get_parameter_name(&self, name: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.disabled_get_parameter_names
|
||||
.remove(&name);
|
||||
}
|
||||
|
||||
pub(crate) fn is_get_parameter_name_enabled(&self, name: GLenum) -> bool {
|
||||
!self
|
||||
.features
|
||||
.borrow()
|
||||
.disabled_get_parameter_names
|
||||
.contains(&name)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_get_tex_parameter_name(&self, name: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.disabled_get_tex_parameter_names
|
||||
.remove(&name);
|
||||
}
|
||||
|
||||
pub(crate) fn is_get_tex_parameter_name_enabled(&self, name: GLenum) -> bool {
|
||||
!self
|
||||
.features
|
||||
.borrow()
|
||||
.disabled_get_tex_parameter_names
|
||||
.contains(&name)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_get_vertex_attrib_name(&self, name: GLenum) {
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.disabled_get_vertex_attrib_names
|
||||
.remove(&name);
|
||||
}
|
||||
|
||||
pub(crate) fn is_get_vertex_attrib_name_enabled(&self, name: GLenum) -> bool {
|
||||
!self
|
||||
.features
|
||||
.borrow()
|
||||
.disabled_get_vertex_attrib_names
|
||||
.contains(&name)
|
||||
}
|
||||
|
||||
pub(crate) fn add_tex_compression_formats(&self, formats: &[TexCompression]) {
|
||||
let formats: FnvHashMap<GLenum, TexCompression> = formats
|
||||
.iter()
|
||||
.map(|&compression| (compression.format.as_gl_constant(), compression))
|
||||
.collect();
|
||||
|
||||
self.features
|
||||
.borrow_mut()
|
||||
.tex_compression_formats
|
||||
.extend(formats.iter());
|
||||
}
|
||||
|
||||
pub(crate) fn get_tex_compression_format(&self, format_id: GLenum) -> Option<TexCompression> {
|
||||
self.features
|
||||
.borrow()
|
||||
.tex_compression_formats
|
||||
.get(&format_id)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_tex_compression_ids(&self) -> Vec<GLenum> {
|
||||
self.features
|
||||
.borrow()
|
||||
.tex_compression_formats
|
||||
.keys()
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn register_all_extensions(&self) {
|
||||
self.register::<ext::angleinstancedarrays::ANGLEInstancedArrays>();
|
||||
self.register::<ext::extblendminmax::EXTBlendMinmax>();
|
||||
self.register::<ext::extcolorbufferhalffloat::EXTColorBufferHalfFloat>();
|
||||
self.register::<ext::extfragdepth::EXTFragDepth>();
|
||||
self.register::<ext::extshadertexturelod::EXTShaderTextureLod>();
|
||||
self.register::<ext::exttexturefilteranisotropic::EXTTextureFilterAnisotropic>();
|
||||
self.register::<ext::oeselementindexuint::OESElementIndexUint>();
|
||||
self.register::<ext::oesstandardderivatives::OESStandardDerivatives>();
|
||||
self.register::<ext::oestexturefloat::OESTextureFloat>();
|
||||
self.register::<ext::oestexturefloatlinear::OESTextureFloatLinear>();
|
||||
self.register::<ext::oestexturehalffloat::OESTextureHalfFloat>();
|
||||
self.register::<ext::oestexturehalffloatlinear::OESTextureHalfFloatLinear>();
|
||||
self.register::<ext::oesvertexarrayobject::OESVertexArrayObject>();
|
||||
self.register::<ext::webglcolorbufferfloat::WEBGLColorBufferFloat>();
|
||||
self.register::<ext::webglcompressedtextureetc1::WEBGLCompressedTextureETC1>();
|
||||
self.register::<ext::webglcompressedtextures3tc::WEBGLCompressedTextureS3TC>();
|
||||
}
|
||||
|
||||
pub(crate) fn enable_element_index_uint(&self) {
|
||||
self.features.borrow_mut().element_index_uint_enabled = true;
|
||||
}
|
||||
|
||||
pub(crate) fn is_element_index_uint_enabled(&self) -> bool {
|
||||
self.features.borrow().element_index_uint_enabled
|
||||
}
|
||||
|
||||
pub(crate) fn enable_blend_minmax(&self) {
|
||||
self.features.borrow_mut().blend_minmax_enabled = true;
|
||||
}
|
||||
|
||||
pub(crate) fn is_blend_minmax_enabled(&self) -> bool {
|
||||
self.features.borrow().blend_minmax_enabled
|
||||
}
|
||||
|
||||
pub(crate) fn is_float_buffer_renderable(&self) -> bool {
|
||||
self.is_enabled::<WEBGLColorBufferFloat>() || self.is_enabled::<OESTextureFloat>()
|
||||
}
|
||||
|
||||
pub(crate) fn is_min_glsl_version_satisfied(&self, min_glsl_version: WebGLSLVersion) -> bool {
|
||||
self.glsl_version >= min_glsl_version
|
||||
}
|
||||
|
||||
pub(crate) fn is_half_float_buffer_renderable(&self) -> bool {
|
||||
self.is_enabled::<EXTColorBufferHalfFloat>() || self.is_enabled::<OESTextureHalfFloat>()
|
||||
}
|
||||
|
||||
pub(crate) fn effective_type(&self, type_: u32) -> u32 {
|
||||
if type_ == OESTextureHalfFloatConstants::HALF_FLOAT_OES &&
|
||||
!self.supports_gl_extension("GL_OES_texture_half_float")
|
||||
{
|
||||
return glow::HALF_FLOAT;
|
||||
}
|
||||
type_
|
||||
}
|
||||
|
||||
pub(crate) fn is_gles(&self) -> bool {
|
||||
self.api_type == GlType::Gles
|
||||
}
|
||||
}
|
||||
|
||||
// Helper structs
|
||||
#[derive(Eq, Hash, MallocSizeOf, PartialEq)]
|
||||
struct TexFormatType(TexFormat, u32);
|
13
components/script/dom/webgl/extensions/mod.rs
Normal file
13
components/script/dom/webgl/extensions/mod.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* 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/. */
|
||||
|
||||
pub(crate) mod ext;
|
||||
mod extension;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod extensions;
|
||||
mod wrapper;
|
||||
|
||||
pub(crate) use self::ext::*;
|
||||
pub(crate) use self::extension::{WebGLExtension, WebGLExtensionSpec};
|
||||
pub(crate) use self::extensions::WebGLExtensions;
|
88
components/script/dom/webgl/extensions/wrapper.rs
Normal file
88
components/script/dom/webgl/extensions/wrapper.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* 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 std::ptr::NonNull;
|
||||
|
||||
use js::jsapi::JSObject;
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
|
||||
use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::MutNullableDom;
|
||||
use crate::dom::bindings::trace::JSTraceable;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
/// Trait used internally by WebGLExtensions to store and
|
||||
/// handle the different WebGL extensions in a common list.
|
||||
pub(crate) trait WebGLExtensionWrapper: JSTraceable + MallocSizeOf {
|
||||
fn instance_or_init(
|
||||
&self,
|
||||
ctx: &WebGLRenderingContext,
|
||||
ext: &WebGLExtensions,
|
||||
) -> NonNull<JSObject>;
|
||||
fn spec(&self) -> WebGLExtensionSpec;
|
||||
fn is_supported(&self, _: &WebGLExtensions) -> bool;
|
||||
fn is_enabled(&self) -> bool;
|
||||
fn enable(&self, ext: &WebGLExtensions);
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
pub(crate) struct TypedWebGLExtensionWrapper<T: WebGLExtension> {
|
||||
extension: MutNullableDom<T::Extension>,
|
||||
}
|
||||
|
||||
/// Typed WebGL Extension implementation.
|
||||
/// Exposes the exact `MutNullableDom<DOMObject>` type defined by the extension.
|
||||
impl<T: WebGLExtension> TypedWebGLExtensionWrapper<T> {
|
||||
pub(crate) fn new() -> TypedWebGLExtensionWrapper<T> {
|
||||
TypedWebGLExtensionWrapper {
|
||||
extension: MutNullableDom::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WebGLExtensionWrapper for TypedWebGLExtensionWrapper<T>
|
||||
where
|
||||
T: WebGLExtension + JSTraceable + MallocSizeOf + 'static,
|
||||
{
|
||||
#[allow(unsafe_code)]
|
||||
fn instance_or_init(
|
||||
&self,
|
||||
ctx: &WebGLRenderingContext,
|
||||
ext: &WebGLExtensions,
|
||||
) -> NonNull<JSObject> {
|
||||
let mut enabled = true;
|
||||
let extension = self.extension.or_init(|| {
|
||||
enabled = false;
|
||||
T::new(ctx, CanGc::note())
|
||||
});
|
||||
if !enabled {
|
||||
self.enable(ext);
|
||||
}
|
||||
unsafe { NonNull::new_unchecked(extension.reflector().get_jsobject().get()) }
|
||||
}
|
||||
|
||||
fn spec(&self) -> WebGLExtensionSpec {
|
||||
T::spec()
|
||||
}
|
||||
|
||||
fn is_supported(&self, ext: &WebGLExtensions) -> bool {
|
||||
self.is_enabled() || T::is_supported(ext)
|
||||
}
|
||||
|
||||
fn is_enabled(&self) -> bool {
|
||||
self.extension.get().is_some()
|
||||
}
|
||||
|
||||
fn enable(&self, ext: &WebGLExtensions) {
|
||||
T::enable(ext);
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
T::name()
|
||||
}
|
||||
}
|
26
components/script/dom/webgl/mod.rs
Normal file
26
components/script/dom/webgl/mod.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* 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/. */
|
||||
|
||||
pub(crate) mod extensions;
|
||||
pub(crate) mod validations;
|
||||
pub(crate) mod vertexarrayobject;
|
||||
pub(crate) mod webgl2renderingcontext;
|
||||
pub(crate) mod webglactiveinfo;
|
||||
pub(crate) mod webglbuffer;
|
||||
pub(crate) mod webglcontextevent;
|
||||
pub(crate) mod webglframebuffer;
|
||||
pub(crate) mod webglobject;
|
||||
pub(crate) mod webglprogram;
|
||||
pub(crate) mod webglquery;
|
||||
pub(crate) mod webglrenderbuffer;
|
||||
pub(crate) mod webglrenderingcontext;
|
||||
pub(crate) mod webglsampler;
|
||||
pub(crate) mod webglshader;
|
||||
pub(crate) mod webglshaderprecisionformat;
|
||||
pub(crate) mod webglsync;
|
||||
pub(crate) mod webgltexture;
|
||||
pub(crate) mod webgltransformfeedback;
|
||||
pub(crate) mod webgluniformlocation;
|
||||
pub(crate) mod webglvertexarrayobject;
|
||||
pub(crate) mod webglvertexarrayobjectoes;
|
14
components/script/dom/webgl/validations/mod.rs
Normal file
14
components/script/dom/webgl/validations/mod.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* 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/. */
|
||||
|
||||
pub(crate) trait WebGLValidator {
|
||||
type ValidatedOutput;
|
||||
type Error: ::std::error::Error;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, Self::Error>;
|
||||
}
|
||||
|
||||
pub(crate) mod tex_image_2d;
|
||||
pub(crate) mod tex_image_3d;
|
||||
pub(crate) mod types;
|
798
components/script/dom/webgl/validations/tex_image_2d.rs
Normal file
798
components/script/dom/webgl/validations/tex_image_2d.rs
Normal file
|
@ -0,0 +1,798 @@
|
|||
/* 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 std::{self, cmp, fmt};
|
||||
|
||||
use canvas_traits::webgl::WebGLError::*;
|
||||
use canvas_traits::webgl::{TexDataType, TexFormat};
|
||||
|
||||
use super::WebGLValidator;
|
||||
use super::types::TexImageTarget;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webgltexture::{
|
||||
ImageInfo, TexCompression, TexCompressionValidation, WebGLTexture,
|
||||
};
|
||||
|
||||
/// The errors that the texImage* family of functions can generate.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum TexImageValidationError {
|
||||
/// An invalid texture target was passed, it contains the invalid target.
|
||||
InvalidTextureTarget(u32),
|
||||
/// The passed texture target was not bound.
|
||||
TextureTargetNotBound(u32),
|
||||
/// Invalid texture dimensions were given.
|
||||
InvalidCubicTextureDimensions,
|
||||
/// A negative level was passed.
|
||||
NegativeLevel,
|
||||
/// A level too high to be allowed by the implementation was passed.
|
||||
LevelTooHigh,
|
||||
/// A level less than an allowed minimal value was passed.
|
||||
LevelTooLow,
|
||||
/// A depth less than an allowed minimal value was passed.
|
||||
DepthTooLow,
|
||||
/// A negative width and height was passed.
|
||||
NegativeDimension,
|
||||
/// A bigger with and height were passed than what the implementation
|
||||
/// allows.
|
||||
TextureTooBig,
|
||||
/// An invalid data type was passed.
|
||||
InvalidDataType,
|
||||
/// An invalid texture format was passed.
|
||||
InvalidTextureFormat,
|
||||
/// Format did not match internal_format.
|
||||
TextureFormatMismatch,
|
||||
/// Invalid data type for the given format.
|
||||
InvalidTypeForFormat,
|
||||
/// Invalid border
|
||||
InvalidBorder,
|
||||
/// Expected a power of two texture.
|
||||
NonPotTexture,
|
||||
/// Unrecognized texture compression format.
|
||||
InvalidCompressionFormat,
|
||||
/// Invalid X/Y texture offset parameters.
|
||||
InvalidOffsets,
|
||||
}
|
||||
|
||||
impl std::error::Error for TexImageValidationError {}
|
||||
|
||||
impl fmt::Display for TexImageValidationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::TexImageValidationError::*;
|
||||
let description = match *self {
|
||||
InvalidTextureTarget(texture_id) => &format!("Invalid texture target ({texture_id})"),
|
||||
TextureTargetNotBound(texture_id) => &format!("Texture was not bound {texture_id}"),
|
||||
InvalidCubicTextureDimensions => {
|
||||
"Invalid dimensions were given for a cubic texture target"
|
||||
},
|
||||
NegativeLevel => "A negative level was passed",
|
||||
LevelTooHigh => "Level too high",
|
||||
LevelTooLow => "Level too low",
|
||||
DepthTooLow => "Depth too low",
|
||||
NegativeDimension => "Negative dimensions were passed",
|
||||
TextureTooBig => "Dimensions given are too big",
|
||||
InvalidDataType => "Invalid data type",
|
||||
InvalidTextureFormat => "Invalid texture format",
|
||||
TextureFormatMismatch => "Texture format mismatch",
|
||||
InvalidTypeForFormat => "Invalid type for the given format",
|
||||
InvalidBorder => "Invalid border",
|
||||
NonPotTexture => "Expected a power of two texture",
|
||||
InvalidCompressionFormat => "Unrecognized texture compression format",
|
||||
InvalidOffsets => "Invalid X/Y texture offset parameters",
|
||||
};
|
||||
write!(f, "TexImageValidationError({})", description)
|
||||
}
|
||||
}
|
||||
|
||||
fn log2(n: u32) -> u32 {
|
||||
31 - n.leading_zeros()
|
||||
}
|
||||
|
||||
pub(crate) struct CommonTexImage2DValidator<'a> {
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
}
|
||||
|
||||
pub(crate) struct CommonTexImage2DValidatorResult {
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) level: u32,
|
||||
pub(crate) internal_format: TexFormat,
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) border: u32,
|
||||
}
|
||||
|
||||
impl WebGLValidator for CommonTexImage2DValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonTexImage2DValidatorResult;
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
// GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D,
|
||||
// GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
// GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
// GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
|
||||
let target = match TexImageTarget::from_gl_constant(self.target) {
|
||||
Some(target) if target.dimensions() == 2 => target,
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureTarget(self.target));
|
||||
},
|
||||
};
|
||||
|
||||
let texture = self
|
||||
.context
|
||||
.textures()
|
||||
.active_texture_for_image_target(target);
|
||||
let limits = self.context.limits();
|
||||
|
||||
let max_size = if target.is_cubic() {
|
||||
limits.max_cube_map_tex_size
|
||||
} else {
|
||||
limits.max_tex_size
|
||||
};
|
||||
|
||||
// If an attempt is made to call this function with no WebGLTexture
|
||||
// bound, an INVALID_OPERATION error is generated.
|
||||
let texture = match texture {
|
||||
Some(texture) => texture,
|
||||
None => {
|
||||
self.context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureTargetNotBound(self.target));
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_ENUM is generated if internal_format is not an accepted
|
||||
// format.
|
||||
let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
|
||||
Some(format)
|
||||
if format.required_webgl_version() <= self.context.webgl_version() &&
|
||||
format.usable_as_internal() =>
|
||||
{
|
||||
format
|
||||
},
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_VALUE is generated if target is one of the six cube map 2D
|
||||
// image targets and the width and height parameters are not equal.
|
||||
if target.is_cubic() && self.width != self.height {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::InvalidCubicTextureDimensions);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE is generated if level is less than 0.
|
||||
if self.level < 0 {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::NegativeLevel);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE is generated if width or height is less than 0
|
||||
if self.width < 0 || self.height < 0 {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::NegativeDimension);
|
||||
}
|
||||
|
||||
let width = self.width as u32;
|
||||
let height = self.height as u32;
|
||||
let level = self.level as u32;
|
||||
|
||||
// GL_INVALID_VALUE is generated if width or height is greater than
|
||||
// GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or
|
||||
// GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D.
|
||||
if width > max_size >> level || height > max_size >> level {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::TextureTooBig);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE is generated if level is greater than zero and the
|
||||
// texture is not power of two.
|
||||
if level > 0 && (!width.is_power_of_two() || !height.is_power_of_two()) {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::NonPotTexture);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE may be generated if level is greater than
|
||||
// log_2(max), where max is the returned value of GL_MAX_TEXTURE_SIZE
|
||||
// when target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE when
|
||||
// target is not GL_TEXTURE_2D.
|
||||
if level > log2(max_size) {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::LevelTooHigh);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE is generated if border is not 0.
|
||||
if self.border != 0 {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::InvalidBorder);
|
||||
}
|
||||
|
||||
Ok(CommonTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border: self.border as u32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CommonTexImage2DValidator<'a> {
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
) -> Self {
|
||||
CommonTexImage2DValidator {
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TexImage2DValidator<'a> {
|
||||
common_validator: CommonTexImage2DValidator<'a>,
|
||||
format: u32,
|
||||
data_type: u32,
|
||||
}
|
||||
|
||||
impl<'a> TexImage2DValidator<'a> {
|
||||
/// TODO: Move data validation logic here.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
format: u32,
|
||||
data_type: u32,
|
||||
) -> Self {
|
||||
TexImage2DValidator {
|
||||
common_validator: CommonTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
),
|
||||
format,
|
||||
data_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The validated result of a TexImage2DValidator-validated call.
|
||||
pub(crate) struct TexImage2DValidatorResult {
|
||||
/// NB: width, height and level are already unsigned after validation.
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) level: u32,
|
||||
pub(crate) border: u32,
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) internal_format: TexFormat,
|
||||
pub(crate) format: TexFormat,
|
||||
pub(crate) data_type: TexDataType,
|
||||
}
|
||||
|
||||
/// TexImage2d validator as per
|
||||
/// <https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml>
|
||||
impl WebGLValidator for TexImage2DValidator<'_> {
|
||||
type ValidatedOutput = TexImage2DValidatorResult;
|
||||
type Error = TexImageValidationError;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.common_validator.context;
|
||||
let CommonTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
} = self.common_validator.validate()?;
|
||||
|
||||
// GL_INVALID_ENUM is generated if format or data_type is not an
|
||||
// accepted value.
|
||||
let data_type = match TexDataType::from_gl_constant(self.data_type) {
|
||||
Some(data_type) if data_type.required_webgl_version() <= context.webgl_version() => {
|
||||
data_type
|
||||
},
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidDataType);
|
||||
},
|
||||
};
|
||||
|
||||
let format = match TexFormat::from_gl_constant(self.format) {
|
||||
Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_OPERATION is generated if format does not match
|
||||
// internal_format.
|
||||
if format != internal_format.to_unsized() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
// NOTE: In WebGL2 data type check should be done based on the internal
|
||||
// format, but in some functions this validator is called with the
|
||||
// regular unsized format as parameter (eg. TexSubImage2D). For now
|
||||
// it's left here to avoid duplication.
|
||||
//
|
||||
// GL_INVALID_OPERATION is generated if type is
|
||||
// GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 and format is
|
||||
// not GL_RGBA.
|
||||
//
|
||||
// GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_5_6_5
|
||||
// and format is not GL_RGB.
|
||||
match data_type {
|
||||
TexDataType::UnsignedShort4444 | TexDataType::UnsignedShort5551
|
||||
if format != TexFormat::RGBA =>
|
||||
{
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::InvalidTypeForFormat);
|
||||
},
|
||||
TexDataType::UnsignedShort565 if format != TexFormat::RGB => {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::InvalidTypeForFormat);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
Ok(TexImage2DValidatorResult {
|
||||
width,
|
||||
height,
|
||||
level,
|
||||
border,
|
||||
texture,
|
||||
target,
|
||||
internal_format,
|
||||
format,
|
||||
data_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CommonCompressedTexImage2DValidator<'a> {
|
||||
common_validator: CommonTexImage2DValidator<'a>,
|
||||
data_len: usize,
|
||||
}
|
||||
|
||||
impl<'a> CommonCompressedTexImage2DValidator<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CommonCompressedTexImage2DValidator {
|
||||
common_validator: CommonTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
compression_format,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
),
|
||||
data_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CommonCompressedTexImage2DValidatorResult {
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) level: u32,
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) compression: TexCompression,
|
||||
}
|
||||
|
||||
fn valid_s3tc_dimension(level: u32, side_length: u32, block_size: u32) -> bool {
|
||||
(side_length % block_size == 0) || (level > 0 && [0, 1, 2].contains(&side_length))
|
||||
}
|
||||
|
||||
fn valid_compressed_data_len(
|
||||
data_len: usize,
|
||||
width: u32,
|
||||
height: u32,
|
||||
compression: &TexCompression,
|
||||
) -> bool {
|
||||
let block_width = compression.block_width as u32;
|
||||
let block_height = compression.block_height as u32;
|
||||
|
||||
let required_blocks_hor = width.div_ceil(block_width);
|
||||
let required_blocks_ver = height.div_ceil(block_height);
|
||||
let required_blocks = required_blocks_hor * required_blocks_ver;
|
||||
|
||||
let required_bytes = required_blocks * compression.bytes_per_block as u32;
|
||||
data_len == required_bytes as usize
|
||||
}
|
||||
|
||||
fn is_subimage_blockaligned(
|
||||
xoffset: u32,
|
||||
yoffset: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
compression: &TexCompression,
|
||||
tex_info: &ImageInfo,
|
||||
) -> bool {
|
||||
let block_width = compression.block_width as u32;
|
||||
let block_height = compression.block_height as u32;
|
||||
|
||||
(xoffset % block_width == 0 && yoffset % block_height == 0) &&
|
||||
(width % block_width == 0 || xoffset + width == tex_info.width()) &&
|
||||
(height % block_height == 0 || yoffset + height == tex_info.height())
|
||||
}
|
||||
|
||||
impl WebGLValidator for CommonCompressedTexImage2DValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.common_validator.context;
|
||||
let CommonTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border: _,
|
||||
} = self.common_validator.validate()?;
|
||||
|
||||
// GL_INVALID_ENUM is generated if internalformat is not a supported
|
||||
// format returned in GL_COMPRESSED_TEXTURE_FORMATS.
|
||||
let compression = context
|
||||
.extension_manager()
|
||||
.get_tex_compression_format(internal_format.as_gl_constant());
|
||||
let compression = match compression {
|
||||
Some(compression) => compression,
|
||||
None => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidCompressionFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_VALUE is generated if imageSize is not consistent with the
|
||||
// format, dimensions, and contents of the specified compressed image data.
|
||||
if !valid_compressed_data_len(self.data_len, width, height, &compression) {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CompressedTexImage2DValidator<'a> {
|
||||
compression_validator: CommonCompressedTexImage2DValidator<'a>,
|
||||
}
|
||||
|
||||
impl<'a> CompressedTexImage2DValidator<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
border: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CompressedTexImage2DValidator {
|
||||
compression_validator: CommonCompressedTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
border,
|
||||
compression_format,
|
||||
data_len,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLValidator for CompressedTexImage2DValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.compression_validator.common_validator.context;
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
} = self.compression_validator.validate()?;
|
||||
|
||||
// GL_INVALID_OPERATION is generated if parameter combinations are not
|
||||
// supported by the specific compressed internal format as specified
|
||||
// in the specific texture compression extension.
|
||||
let compression_valid = match compression.validation {
|
||||
TexCompressionValidation::S3TC => {
|
||||
let valid_width =
|
||||
valid_s3tc_dimension(level, width, compression.block_width as u32);
|
||||
let valid_height =
|
||||
valid_s3tc_dimension(level, height, compression.block_height as u32);
|
||||
valid_width && valid_height
|
||||
},
|
||||
TexCompressionValidation::None => true,
|
||||
};
|
||||
if !compression_valid {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CompressedTexSubImage2DValidator<'a> {
|
||||
compression_validator: CommonCompressedTexImage2DValidator<'a>,
|
||||
xoffset: i32,
|
||||
yoffset: i32,
|
||||
}
|
||||
|
||||
impl<'a> CompressedTexSubImage2DValidator<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
xoffset: i32,
|
||||
yoffset: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
compression_format: u32,
|
||||
data_len: usize,
|
||||
) -> Self {
|
||||
CompressedTexSubImage2DValidator {
|
||||
compression_validator: CommonCompressedTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
compression_format,
|
||||
data_len,
|
||||
),
|
||||
xoffset,
|
||||
yoffset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLValidator for CompressedTexSubImage2DValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonCompressedTexImage2DValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.compression_validator.common_validator.context;
|
||||
let CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
} = self.compression_validator.validate()?;
|
||||
|
||||
let tex_info = texture.image_info_for_target(&target, level).unwrap();
|
||||
|
||||
// GL_INVALID_VALUE is generated if:
|
||||
// - xoffset or yoffset is less than 0
|
||||
// - x offset plus the width is greater than the texture width
|
||||
// - y offset plus the height is greater than the texture height
|
||||
if self.xoffset < 0 ||
|
||||
(self.xoffset as u32 + width) > tex_info.width() ||
|
||||
self.yoffset < 0 ||
|
||||
(self.yoffset as u32 + height) > tex_info.height()
|
||||
{
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::InvalidOffsets);
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if format does not match
|
||||
// internal_format.
|
||||
if compression.format != tex_info.internal_format() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if parameter combinations are not
|
||||
// supported by the specific compressed internal format as specified
|
||||
// in the specific texture compression extension.
|
||||
let compression_valid = match compression.validation {
|
||||
TexCompressionValidation::S3TC => is_subimage_blockaligned(
|
||||
self.xoffset as u32,
|
||||
self.yoffset as u32,
|
||||
width,
|
||||
height,
|
||||
&compression,
|
||||
&tex_info,
|
||||
),
|
||||
TexCompressionValidation::None => true,
|
||||
};
|
||||
if !compression_valid {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
Ok(CommonCompressedTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
width,
|
||||
height,
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TexStorageValidator<'a> {
|
||||
common_validator: CommonTexImage2DValidator<'a>,
|
||||
dimensions: u8,
|
||||
depth: i32,
|
||||
}
|
||||
|
||||
pub(crate) struct TexStorageValidatorResult {
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) levels: u32,
|
||||
pub(crate) internal_format: TexFormat,
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) depth: u32,
|
||||
}
|
||||
|
||||
impl<'a> TexStorageValidator<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
dimensions: u8,
|
||||
target: u32,
|
||||
levels: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
) -> Self {
|
||||
TexStorageValidator {
|
||||
common_validator: CommonTexImage2DValidator::new(
|
||||
context,
|
||||
target,
|
||||
levels,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
),
|
||||
dimensions,
|
||||
depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLValidator for TexStorageValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = TexStorageValidatorResult;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.common_validator.context;
|
||||
let CommonTexImage2DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
border: _,
|
||||
} = self.common_validator.validate()?;
|
||||
|
||||
if self.depth < 1 {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::DepthTooLow);
|
||||
}
|
||||
if level < 1 {
|
||||
context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::LevelTooLow);
|
||||
}
|
||||
|
||||
let dimensions_valid = match target {
|
||||
TexImageTarget::Texture2D | TexImageTarget::CubeMap => self.dimensions == 2,
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => self.dimensions == 3,
|
||||
_ => false,
|
||||
};
|
||||
if !dimensions_valid {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureTarget(
|
||||
target.as_gl_constant(),
|
||||
));
|
||||
}
|
||||
|
||||
if !internal_format.is_sized() {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
}
|
||||
|
||||
let max_level = log2(cmp::max(width, height)) + 1;
|
||||
if level > max_level {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::LevelTooHigh);
|
||||
}
|
||||
|
||||
if texture.target().is_none() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureTargetNotBound(
|
||||
target.as_gl_constant(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(TexStorageValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
levels: level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth: self.depth as u32,
|
||||
})
|
||||
}
|
||||
}
|
311
components/script/dom/webgl/validations/tex_image_3d.rs
Normal file
311
components/script/dom/webgl/validations/tex_image_3d.rs
Normal file
|
@ -0,0 +1,311 @@
|
|||
/* 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::WebGLError::*;
|
||||
use canvas_traits::webgl::{TexDataType, TexFormat};
|
||||
use js::jsapi::Type;
|
||||
use js::typedarray::ArrayBufferView;
|
||||
|
||||
use super::WebGLValidator;
|
||||
use super::tex_image_2d::TexImageValidationError;
|
||||
use super::types::TexImageTarget;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
use crate::dom::webgl::webgltexture::WebGLTexture;
|
||||
|
||||
fn log2(n: u32) -> u32 {
|
||||
31 - n.leading_zeros()
|
||||
}
|
||||
|
||||
pub(crate) struct CommonTexImage3DValidator<'a> {
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
border: i32,
|
||||
}
|
||||
|
||||
pub(crate) struct CommonTexImage3DValidatorResult {
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) level: u32,
|
||||
pub(crate) internal_format: TexFormat,
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) depth: u32,
|
||||
pub(crate) border: u32,
|
||||
}
|
||||
|
||||
impl WebGLValidator for CommonTexImage3DValidator<'_> {
|
||||
type Error = TexImageValidationError;
|
||||
type ValidatedOutput = CommonTexImage3DValidatorResult;
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
// GL_INVALID_ENUM is generated if target is not GL_TEXTURE_3D or GL_TEXTURE_2D_ARRAY.
|
||||
let target = match TexImageTarget::from_gl_constant(self.target) {
|
||||
Some(target) if target.dimensions() == 3 => target,
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureTarget(self.target));
|
||||
},
|
||||
};
|
||||
|
||||
let texture = self
|
||||
.context
|
||||
.textures()
|
||||
.active_texture_for_image_target(target);
|
||||
let limits = self.context.limits();
|
||||
|
||||
let max_size = limits.max_3d_tex_size;
|
||||
|
||||
// If an attempt is made to call this function with no WebGLTexture
|
||||
// bound, an INVALID_OPERATION error is generated.
|
||||
let texture = match texture {
|
||||
Some(texture) => texture,
|
||||
None => {
|
||||
self.context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureTargetNotBound(self.target));
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_ENUM is generated if internal_format is not an accepted
|
||||
// format.
|
||||
let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
|
||||
Some(format)
|
||||
if format.required_webgl_version() <= self.context.webgl_version() &&
|
||||
format.usable_as_internal() =>
|
||||
{
|
||||
format
|
||||
},
|
||||
_ => {
|
||||
self.context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_VALUE is generated if width, height, or depth is less than 0 or greater than
|
||||
// GL_MAX_3D_TEXTURE_SIZE.
|
||||
if self.width < 0 || self.height < 0 || self.depth < 0 {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::NegativeDimension);
|
||||
}
|
||||
let width = self.width as u32;
|
||||
let height = self.height as u32;
|
||||
let depth = self.depth as u32;
|
||||
let level = self.level as u32;
|
||||
if width > max_size || height > max_size || level > max_size {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::TextureTooBig);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE may be generated if level is greater than log2(max),
|
||||
// where max is the returned value of GL_MAX_3D_TEXTURE_SIZE.
|
||||
if self.level < 0 {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::NegativeLevel);
|
||||
}
|
||||
if level > log2(max_size) {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::LevelTooHigh);
|
||||
}
|
||||
|
||||
// GL_INVALID_VALUE is generated if border is not 0 or 1.
|
||||
if !(self.border == 0 || self.border == 1) {
|
||||
self.context.webgl_error(InvalidValue);
|
||||
return Err(TexImageValidationError::InvalidBorder);
|
||||
}
|
||||
|
||||
Ok(CommonTexImage3DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
border: self.border as u32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CommonTexImage3DValidator<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
border: i32,
|
||||
) -> Self {
|
||||
CommonTexImage3DValidator {
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
border,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TexImage3DValidator<'a> {
|
||||
common_validator: CommonTexImage3DValidator<'a>,
|
||||
format: u32,
|
||||
data_type: u32,
|
||||
data: &'a Option<ArrayBufferView>,
|
||||
}
|
||||
|
||||
impl<'a> TexImage3DValidator<'a> {
|
||||
/// TODO: Move data validation logic here.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
context: &'a WebGLRenderingContext,
|
||||
target: u32,
|
||||
level: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
depth: i32,
|
||||
border: i32,
|
||||
format: u32,
|
||||
data_type: u32,
|
||||
data: &'a Option<ArrayBufferView>,
|
||||
) -> Self {
|
||||
TexImage3DValidator {
|
||||
common_validator: CommonTexImage3DValidator::new(
|
||||
context,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
border,
|
||||
),
|
||||
format,
|
||||
data_type,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The validated result of a TexImage2DValidator-validated call.
|
||||
pub(crate) struct TexImage3DValidatorResult {
|
||||
/// NB: width, height and level are already unsigned after validation.
|
||||
pub(crate) width: u32,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) depth: u32,
|
||||
pub(crate) level: u32,
|
||||
pub(crate) border: u32,
|
||||
pub(crate) texture: DomRoot<WebGLTexture>,
|
||||
pub(crate) target: TexImageTarget,
|
||||
pub(crate) internal_format: TexFormat,
|
||||
pub(crate) format: TexFormat,
|
||||
pub(crate) data_type: TexDataType,
|
||||
}
|
||||
|
||||
/// TexImage3d validator as per
|
||||
/// <https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage3D.xml>
|
||||
impl WebGLValidator for TexImage3DValidator<'_> {
|
||||
type ValidatedOutput = TexImage3DValidatorResult;
|
||||
type Error = TexImageValidationError;
|
||||
|
||||
fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
|
||||
let context = self.common_validator.context;
|
||||
let CommonTexImage3DValidatorResult {
|
||||
texture,
|
||||
target,
|
||||
level,
|
||||
internal_format,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
border,
|
||||
} = self.common_validator.validate()?;
|
||||
|
||||
// GL_INVALID_ENUM is generated if format is not an accepted format constant.
|
||||
// Format constants other than GL_STENCIL_INDEX and GL_DEPTH_COMPONENT are accepted.
|
||||
let data_type = match TexDataType::from_gl_constant(self.data_type) {
|
||||
Some(data_type) if data_type.required_webgl_version() <= context.webgl_version() => {
|
||||
data_type
|
||||
},
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidDataType);
|
||||
},
|
||||
};
|
||||
let format = match TexFormat::from_gl_constant(self.format) {
|
||||
Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
|
||||
_ => {
|
||||
context.webgl_error(InvalidEnum);
|
||||
return Err(TexImageValidationError::InvalidTextureFormat);
|
||||
},
|
||||
};
|
||||
|
||||
// GL_INVALID_OPERATION is generated if format does not match
|
||||
// internal_format.
|
||||
if format != internal_format.to_unsized() {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
if !internal_format.compatible_data_types().contains(&data_type) {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::TextureFormatMismatch);
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if target is GL_TEXTURE_3D and
|
||||
// format is GL_DEPTH_COMPONENT, or GL_DEPTH_STENCIL.
|
||||
if target == TexImageTarget::Texture3D &&
|
||||
(format == TexFormat::DepthComponent || format == TexFormat::DepthStencil)
|
||||
{
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::InvalidTypeForFormat);
|
||||
}
|
||||
|
||||
// If srcData is non-null, the type of srcData must match the type according to
|
||||
// the above table; otherwise, generate an INVALID_OPERATION error.
|
||||
let element_size = data_type.element_size();
|
||||
let received_size = match self.data {
|
||||
Some(buf) => match buf.get_array_type() {
|
||||
Type::Int8 => 1,
|
||||
Type::Uint8 => 1,
|
||||
Type::Int16 => 2,
|
||||
Type::Uint16 => 2,
|
||||
Type::Int32 => 4,
|
||||
Type::Uint32 => 4,
|
||||
Type::Float32 => 4,
|
||||
_ => {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::InvalidTypeForFormat);
|
||||
},
|
||||
},
|
||||
None => element_size,
|
||||
};
|
||||
if received_size != element_size {
|
||||
context.webgl_error(InvalidOperation);
|
||||
return Err(TexImageValidationError::InvalidTypeForFormat);
|
||||
}
|
||||
|
||||
Ok(TexImage3DValidatorResult {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
level,
|
||||
border,
|
||||
texture,
|
||||
target,
|
||||
internal_format,
|
||||
format,
|
||||
data_type,
|
||||
})
|
||||
}
|
||||
}
|
36
components/script/dom/webgl/validations/types.rs
Normal file
36
components/script/dom/webgl/validations/types.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* 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::gl_enums;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
|
||||
gl_enums! {
|
||||
pub enum TexImageTarget {
|
||||
Texture2D = constants::TEXTURE_2D,
|
||||
Texture2DArray = constants::TEXTURE_2D_ARRAY,
|
||||
Texture3D = constants::TEXTURE_3D,
|
||||
CubeMap = constants::TEXTURE_CUBE_MAP,
|
||||
CubeMapPositiveX = constants::TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
CubeMapNegativeX = constants::TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
CubeMapPositiveY = constants::TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
CubeMapNegativeY = constants::TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
CubeMapPositiveZ = constants::TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
CubeMapNegativeZ = constants::TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
}
|
||||
}
|
||||
|
||||
impl TexImageTarget {
|
||||
pub(crate) fn is_cubic(&self) -> bool {
|
||||
!matches!(*self, TexImageTarget::Texture2D)
|
||||
}
|
||||
|
||||
pub(crate) fn dimensions(self) -> u8 {
|
||||
match self {
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => 3,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
}
|
316
components/script/dom/webgl/vertexarrayobject.rs
Normal file
316
components/script/dom/webgl/vertexarrayobject.rs
Normal file
|
@ -0,0 +1,316 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{
|
||||
ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVersion, WebGLVertexArrayId,
|
||||
};
|
||||
|
||||
use crate::dom::bindings::cell::{DomRefCell, Ref};
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants2;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use crate::dom::bindings::root::{Dom, MutNullableDom};
|
||||
use crate::dom::webgl::webglbuffer::WebGLBuffer;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
pub(crate) struct VertexArrayObject {
|
||||
context: Dom<WebGLRenderingContext>,
|
||||
#[no_trace]
|
||||
id: Option<WebGLVertexArrayId>,
|
||||
ever_bound: Cell<bool>,
|
||||
is_deleted: Cell<bool>,
|
||||
vertex_attribs: DomRefCell<Box<[VertexAttribData]>>,
|
||||
element_array_buffer: MutNullableDom<WebGLBuffer>,
|
||||
}
|
||||
|
||||
impl VertexArrayObject {
|
||||
pub(crate) fn new(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
|
||||
let max_vertex_attribs = context.limits().max_vertex_attribs as usize;
|
||||
Self {
|
||||
context: Dom::from_ref(context),
|
||||
id,
|
||||
ever_bound: Default::default(),
|
||||
is_deleted: Default::default(),
|
||||
vertex_attribs: DomRefCell::new(vec![Default::default(); max_vertex_attribs].into()),
|
||||
element_array_buffer: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> Option<WebGLVertexArrayId> {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.is_deleted.get()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
assert!(self.id.is_some());
|
||||
if self.is_deleted.get() {
|
||||
return;
|
||||
}
|
||||
self.is_deleted.set(true);
|
||||
let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => self.context.send_command_ignored(cmd),
|
||||
Operation::Infallible => self.context.send_command(cmd),
|
||||
}
|
||||
|
||||
for attrib_data in &**self.vertex_attribs.borrow() {
|
||||
if let Some(buffer) = attrib_data.buffer() {
|
||||
buffer.decrement_attached_counter(operation_fallibility);
|
||||
}
|
||||
}
|
||||
if let Some(buffer) = self.element_array_buffer.get() {
|
||||
buffer.decrement_attached_counter(operation_fallibility);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn ever_bound(&self) -> bool {
|
||||
self.ever_bound.get()
|
||||
}
|
||||
|
||||
pub(crate) fn set_ever_bound(&self) {
|
||||
self.ever_bound.set(true);
|
||||
}
|
||||
|
||||
pub(crate) fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
|
||||
&self.element_array_buffer
|
||||
}
|
||||
|
||||
pub(crate) fn get_vertex_attrib(&self, index: u32) -> Option<Ref<'_, VertexAttribData>> {
|
||||
Ref::filter_map(self.vertex_attribs.borrow(), |attribs| {
|
||||
attribs.get(index as usize)
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub(crate) fn set_vertex_attrib_type(&self, index: u32, type_: u32) {
|
||||
self.vertex_attribs.borrow_mut()[index as usize].type_ = type_;
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_pointer(
|
||||
&self,
|
||||
index: u32,
|
||||
size: i32,
|
||||
type_: u32,
|
||||
normalized: bool,
|
||||
stride: i32,
|
||||
offset: i64,
|
||||
) -> WebGLResult<()> {
|
||||
let mut attribs = self.vertex_attribs.borrow_mut();
|
||||
let data = attribs
|
||||
.get_mut(index as usize)
|
||||
.ok_or(WebGLError::InvalidValue)?;
|
||||
|
||||
if !(1..=4).contains(&size) {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
|
||||
if !(0..=255).contains(&stride) || offset < 0 {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
let is_webgl2 = matches!(self.context.webgl_version(), WebGLVersion::WebGL2);
|
||||
|
||||
let bytes_per_component: i32 = match type_ {
|
||||
constants::BYTE | constants::UNSIGNED_BYTE => 1,
|
||||
constants::SHORT | constants::UNSIGNED_SHORT => 2,
|
||||
constants::FLOAT => 4,
|
||||
constants::INT | constants::UNSIGNED_INT if is_webgl2 => 4,
|
||||
constants2::HALF_FLOAT if is_webgl2 => 2,
|
||||
glow::FIXED if is_webgl2 => 4,
|
||||
constants2::INT_2_10_10_10_REV | constants2::UNSIGNED_INT_2_10_10_10_REV
|
||||
if is_webgl2 && size == 4 =>
|
||||
{
|
||||
4
|
||||
},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
let buffer = self.context.array_buffer();
|
||||
match buffer {
|
||||
Some(ref buffer) => buffer.increment_attached_counter(),
|
||||
None if offset != 0 => {
|
||||
// https://github.com/KhronosGroup/WebGL/pull/2228
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
self.context.send_command(WebGLCommand::VertexAttribPointer(
|
||||
index,
|
||||
size,
|
||||
type_,
|
||||
normalized,
|
||||
stride,
|
||||
offset as u32,
|
||||
));
|
||||
if let Some(old) = data.buffer() {
|
||||
old.decrement_attached_counter(Operation::Infallible);
|
||||
}
|
||||
|
||||
*data = VertexAttribData {
|
||||
enabled_as_array: data.enabled_as_array,
|
||||
size: size as u8,
|
||||
type_,
|
||||
bytes_per_vertex: size as u8 * bytes_per_component as u8,
|
||||
normalized,
|
||||
stride: stride as u8,
|
||||
offset: offset as u32,
|
||||
buffer: buffer.map(|b| Dom::from_ref(&*b)),
|
||||
divisor: data.divisor,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_divisor(&self, index: u32, value: u32) {
|
||||
self.vertex_attribs.borrow_mut()[index as usize].divisor = value;
|
||||
}
|
||||
|
||||
pub(crate) fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
|
||||
self.vertex_attribs.borrow_mut()[index as usize].enabled_as_array = value;
|
||||
}
|
||||
|
||||
pub(crate) fn unbind_buffer(&self, buffer: &WebGLBuffer) {
|
||||
for attrib in &mut **self.vertex_attribs.borrow_mut() {
|
||||
if let Some(b) = attrib.buffer() {
|
||||
if b.id() != buffer.id() {
|
||||
continue;
|
||||
}
|
||||
b.decrement_attached_counter(Operation::Infallible);
|
||||
}
|
||||
attrib.buffer = None;
|
||||
}
|
||||
if self
|
||||
.element_array_buffer
|
||||
.get()
|
||||
.is_some_and(|b| buffer == &*b)
|
||||
{
|
||||
buffer.decrement_attached_counter(Operation::Infallible);
|
||||
self.element_array_buffer.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate_for_draw(
|
||||
&self,
|
||||
required_len: u32,
|
||||
instance_count: u32,
|
||||
active_attribs: &[ActiveAttribInfo],
|
||||
) -> WebGLResult<()> {
|
||||
// TODO(nox): Cache limits per VAO.
|
||||
let attribs = self.vertex_attribs.borrow();
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
|
||||
if attribs
|
||||
.iter()
|
||||
.any(|data| data.enabled_as_array && data.buffer.is_none())
|
||||
{
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
let mut has_active_attrib = false;
|
||||
let mut has_divisor_0 = false;
|
||||
for active_info in active_attribs {
|
||||
let Some(location) = active_info.location else {
|
||||
continue;
|
||||
};
|
||||
has_active_attrib = true;
|
||||
let attrib = &attribs[location as usize];
|
||||
if attrib.divisor == 0 {
|
||||
has_divisor_0 = true;
|
||||
}
|
||||
if !attrib.enabled_as_array {
|
||||
continue;
|
||||
}
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
|
||||
if required_len > 0 && instance_count > 0 {
|
||||
let max_vertices = attrib.max_vertices();
|
||||
if attrib.divisor == 0 {
|
||||
if max_vertices < required_len {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
} else if max_vertices
|
||||
.checked_mul(attrib.divisor)
|
||||
.is_some_and(|v| v < instance_count)
|
||||
{
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_active_attrib && !has_divisor_0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VertexArrayObject {
|
||||
fn drop(&mut self) {
|
||||
if self.id.is_some() {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
pub(crate) struct VertexAttribData {
|
||||
pub(crate) enabled_as_array: bool,
|
||||
pub(crate) size: u8,
|
||||
pub(crate) type_: u32,
|
||||
bytes_per_vertex: u8,
|
||||
pub(crate) normalized: bool,
|
||||
pub(crate) stride: u8,
|
||||
pub(crate) offset: u32,
|
||||
pub(crate) buffer: Option<Dom<WebGLBuffer>>,
|
||||
pub(crate) divisor: u32,
|
||||
}
|
||||
|
||||
impl Default for VertexAttribData {
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled_as_array: false,
|
||||
size: 4,
|
||||
type_: constants::FLOAT,
|
||||
bytes_per_vertex: 16,
|
||||
normalized: false,
|
||||
stride: 0,
|
||||
offset: 0,
|
||||
buffer: None,
|
||||
divisor: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VertexAttribData {
|
||||
pub(crate) fn buffer(&self) -> Option<&WebGLBuffer> {
|
||||
self.buffer.as_deref()
|
||||
}
|
||||
|
||||
pub(crate) fn max_vertices(&self) -> u32 {
|
||||
let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
|
||||
if capacity < self.bytes_per_vertex as u32 {
|
||||
0
|
||||
} else if self.stride == 0 {
|
||||
capacity / self.bytes_per_vertex as u32
|
||||
} else if self.stride < self.bytes_per_vertex {
|
||||
(capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
|
||||
} else {
|
||||
let mut max = capacity / self.stride as u32;
|
||||
if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
|
||||
max += 1;
|
||||
}
|
||||
max
|
||||
}
|
||||
}
|
||||
}
|
4922
components/script/dom/webgl/webgl2renderingcontext.rs
Normal file
4922
components/script/dom/webgl/webgl2renderingcontext.rs
Normal file
File diff suppressed because it is too large
Load diff
64
components/script/dom/webgl/webglactiveinfo.rs
Normal file
64
components/script/dom/webgl/webglactiveinfo.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoMethods;
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLActiveInfo {
|
||||
reflector_: Reflector,
|
||||
size: i32,
|
||||
// NOTE: `ty` stands for `type`, which is a reserved keyword
|
||||
ty: u32,
|
||||
name: DOMString,
|
||||
}
|
||||
|
||||
impl WebGLActiveInfo {
|
||||
fn new_inherited(size: i32, ty: u32, name: DOMString) -> WebGLActiveInfo {
|
||||
WebGLActiveInfo {
|
||||
reflector_: Reflector::new(),
|
||||
size,
|
||||
ty,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
size: i32,
|
||||
ty: u32,
|
||||
name: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<WebGLActiveInfo> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLActiveInfo::new_inherited(size, ty, name)),
|
||||
window,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLActiveInfoMethods<crate::DomTypeHolder> for WebGLActiveInfo {
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.11.1
|
||||
fn Size(&self) -> i32 {
|
||||
self.size
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.11.1
|
||||
fn Type(&self) -> u32 {
|
||||
self.ty
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.11.1
|
||||
fn Name(&self) -> DOMString {
|
||||
self.name.clone()
|
||||
}
|
||||
}
|
265
components/script/dom/webgl/webglbuffer.rs
Normal file
265
components/script/dom/webgl/webglbuffer.rs
Normal file
|
@ -0,0 +1,265 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLResult, webgl_channel};
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc;
|
||||
use script_bindings::weakref::WeakRef;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
fn target_is_copy_buffer(target: u32) -> bool {
|
||||
target == WebGL2RenderingContextConstants::COPY_READ_BUFFER ||
|
||||
target == WebGL2RenderingContextConstants::COPY_WRITE_BUFFER
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct DroppableWebGLBuffer {
|
||||
#[no_trace]
|
||||
id: WebGLBufferId,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
attached_counter: Cell<u32>,
|
||||
context: WeakRef<WebGLRenderingContext>,
|
||||
}
|
||||
|
||||
impl DroppableWebGLBuffer {
|
||||
pub(crate) fn new(
|
||||
id: WebGLBufferId,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
attached_counter: Cell<u32>,
|
||||
context: WeakRef<WebGLRenderingContext>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
marked_for_deletion,
|
||||
attached_counter,
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DroppableWebGLBuffer {
|
||||
pub(crate) fn is_marked_for_deletion(&self) -> bool {
|
||||
self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn set_marked_for_deletion(&self, marked_for_deletion: bool) {
|
||||
self.marked_for_deletion.set(marked_for_deletion);
|
||||
}
|
||||
|
||||
pub(crate) fn get_attached_counter(&self) -> u32 {
|
||||
self.attached_counter.get()
|
||||
}
|
||||
|
||||
pub(crate) fn set_attached_counter(&self, attached_counter: u32) {
|
||||
self.attached_counter.set(attached_counter);
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> WebGLBufferId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn is_attached(&self) -> bool {
|
||||
self.get_attached_counter() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.is_marked_for_deletion() && !self.is_attached()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
assert!(self.is_deleted());
|
||||
if let Some(context) = self.context.root() {
|
||||
let cmd = WebGLCommand::DeleteBuffer(self.id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) {
|
||||
if self.is_marked_for_deletion() {
|
||||
return;
|
||||
}
|
||||
self.set_marked_for_deletion(true);
|
||||
if self.is_deleted() {
|
||||
self.delete(operation_fallibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DroppableWebGLBuffer {
|
||||
fn drop(&mut self) {
|
||||
self.mark_for_deletion(Operation::Fallible);
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLBuffer {
|
||||
webgl_object: WebGLObject,
|
||||
/// The target to which this buffer was bound the first time
|
||||
target: Cell<Option<u32>>,
|
||||
capacity: Cell<usize>,
|
||||
/// <https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetBufferParameteriv.xml>
|
||||
usage: Cell<u32>,
|
||||
droppable: DroppableWebGLBuffer,
|
||||
}
|
||||
|
||||
impl WebGLBuffer {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLBufferId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
target: Default::default(),
|
||||
capacity: Default::default(),
|
||||
usage: Cell::new(WebGLRenderingContextConstants::STATIC_DRAW),
|
||||
droppable: DroppableWebGLBuffer::new(
|
||||
id,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
WeakRef::new(context),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_new(
|
||||
context: &WebGLRenderingContext,
|
||||
can_gc: CanGc,
|
||||
) -> Option<DomRoot<Self>> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateBuffer(sender));
|
||||
receiver
|
||||
.recv()
|
||||
.unwrap()
|
||||
.map(|id| WebGLBuffer::new(context, id, can_gc))
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLBufferId,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLBuffer::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLBuffer {
|
||||
pub(crate) fn id(&self) -> WebGLBufferId {
|
||||
self.droppable.id()
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> {
|
||||
match usage {
|
||||
WebGLRenderingContextConstants::STREAM_DRAW |
|
||||
WebGLRenderingContextConstants::STATIC_DRAW |
|
||||
WebGLRenderingContextConstants::DYNAMIC_DRAW |
|
||||
WebGL2RenderingContextConstants::STATIC_READ |
|
||||
WebGL2RenderingContextConstants::DYNAMIC_READ |
|
||||
WebGL2RenderingContextConstants::STREAM_READ |
|
||||
WebGL2RenderingContextConstants::STATIC_COPY |
|
||||
WebGL2RenderingContextConstants::DYNAMIC_COPY |
|
||||
WebGL2RenderingContextConstants::STREAM_COPY => (),
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
}
|
||||
|
||||
self.capacity.set(data.len());
|
||||
self.usage.set(usage);
|
||||
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::BufferData(target, receiver, usage));
|
||||
sender.send(data).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn capacity(&self) -> usize {
|
||||
self.capacity.get()
|
||||
}
|
||||
|
||||
pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) {
|
||||
self.droppable.mark_for_deletion(operation_fallibility);
|
||||
}
|
||||
|
||||
fn delete(&self, operation_fallibility: Operation) {
|
||||
self.droppable.delete(operation_fallibility);
|
||||
}
|
||||
|
||||
pub(crate) fn is_marked_for_deletion(&self) -> bool {
|
||||
self.droppable.is_marked_for_deletion()
|
||||
}
|
||||
|
||||
fn get_attached_counter(&self) -> u32 {
|
||||
self.droppable.get_attached_counter()
|
||||
}
|
||||
|
||||
fn set_attached_counter(&self, attached_counter: u32) {
|
||||
self.droppable.set_attached_counter(attached_counter);
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.droppable.is_deleted()
|
||||
}
|
||||
|
||||
pub(crate) fn target(&self) -> Option<u32> {
|
||||
self.target.get()
|
||||
}
|
||||
|
||||
fn can_bind_to(&self, new_target: u32) -> bool {
|
||||
if let Some(current_target) = self.target.get() {
|
||||
if [current_target, new_target]
|
||||
.contains(&WebGLRenderingContextConstants::ELEMENT_ARRAY_BUFFER)
|
||||
{
|
||||
return target_is_copy_buffer(new_target) || new_target == current_target;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn set_target_maybe(&self, target: u32) -> WebGLResult<()> {
|
||||
if !self.can_bind_to(target) {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
if !target_is_copy_buffer(target) {
|
||||
self.target.set(Some(target));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn increment_attached_counter(&self) {
|
||||
self.set_attached_counter(
|
||||
self.get_attached_counter()
|
||||
.checked_add(1)
|
||||
.expect("refcount overflowed"),
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn decrement_attached_counter(&self, operation_fallibility: Operation) {
|
||||
self.set_attached_counter(
|
||||
self.get_attached_counter()
|
||||
.checked_sub(1)
|
||||
.expect("refcount underflowed"),
|
||||
);
|
||||
if self.is_deleted() {
|
||||
self.delete(operation_fallibility);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn usage(&self) -> u32 {
|
||||
self.usage.get()
|
||||
}
|
||||
}
|
118
components/script/dom/webgl/webglcontextevent.rs
Normal file
118
components/script/dom/webgl/webglcontextevent.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLContextEventBinding::{
|
||||
WebGLContextEventInit, WebGLContextEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLContextEvent {
|
||||
event: Event,
|
||||
status_message: DOMString,
|
||||
}
|
||||
|
||||
impl WebGLContextEventMethods<crate::DomTypeHolder> for WebGLContextEvent {
|
||||
// https://registry.khronos.org/webgl/specs/latest/1.0/#5.15
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
type_: DOMString,
|
||||
init: &WebGLContextEventInit,
|
||||
) -> Fallible<DomRoot<WebGLContextEvent>> {
|
||||
let status_message = match init.statusMessage.as_ref() {
|
||||
Some(message) => message.clone(),
|
||||
None => DOMString::new(),
|
||||
};
|
||||
|
||||
let bubbles = EventBubbles::from(init.parent.bubbles);
|
||||
|
||||
let cancelable = EventCancelable::from(init.parent.cancelable);
|
||||
|
||||
Ok(WebGLContextEvent::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
Atom::from(type_),
|
||||
bubbles,
|
||||
cancelable,
|
||||
status_message,
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15
|
||||
fn StatusMessage(&self) -> DOMString {
|
||||
self.status_message.clone()
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLContextEvent {
|
||||
fn new_inherited(status_message: DOMString) -> WebGLContextEvent {
|
||||
WebGLContextEvent {
|
||||
event: Event::new_inherited(),
|
||||
status_message,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
status_message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<WebGLContextEvent> {
|
||||
Self::new_with_proto(
|
||||
window,
|
||||
None,
|
||||
type_,
|
||||
bubbles,
|
||||
cancelable,
|
||||
status_message,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
status_message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<WebGLContextEvent> {
|
||||
let event = reflect_dom_object_with_proto(
|
||||
Box::new(WebGLContextEvent::new_inherited(status_message)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
|
||||
{
|
||||
let parent = event.upcast::<Event>();
|
||||
parent.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||
}
|
||||
|
||||
event
|
||||
}
|
||||
}
|
1082
components/script/dom/webgl/webglframebuffer.rs
Normal file
1082
components/script/dom/webgl/webglframebuffer.rs
Normal file
File diff suppressed because it is too large
Load diff
46
components/script/dom/webgl/webglobject.rs
Normal file
46
components/script/dom/webgl/webglobject.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLObjectBinding::WebGLObjectMethods;
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
use crate::dom::bindings::root::Dom;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLObject {
|
||||
reflector_: Reflector,
|
||||
context: Dom<WebGLRenderingContext>,
|
||||
label: DomRefCell<USVString>,
|
||||
}
|
||||
|
||||
impl WebGLObject {
|
||||
pub(crate) fn new_inherited(context: &WebGLRenderingContext) -> WebGLObject {
|
||||
WebGLObject {
|
||||
reflector_: Reflector::new(),
|
||||
context: Dom::from_ref(context),
|
||||
label: DomRefCell::new(USVString::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn context(&self) -> &WebGLRenderingContext {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLObjectMethods<crate::DomTypeHolder> for WebGLObject {
|
||||
/// <https://registry.khronos.org/webgl/specs/latest/1.0/#5.3>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://registry.khronos.org/webgl/specs/latest/1.0/#5.3>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
749
components/script/dom/webgl/webglprogram.rs
Normal file
749
components/script/dom/webgl/webglprogram.rs
Normal file
|
@ -0,0 +1,749 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{
|
||||
ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, WebGLCommand, WebGLError,
|
||||
WebGLProgramId, WebGLResult, webgl_channel,
|
||||
};
|
||||
use dom_struct::dom_struct;
|
||||
use fnv::FnvHashSet;
|
||||
|
||||
use crate::canvas_context::CanvasContext;
|
||||
use crate::dom::bindings::cell::{DomRefCell, Ref};
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants2;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::webgl::webglactiveinfo::WebGLActiveInfo;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::dom::webgl::webglshader::WebGLShader;
|
||||
use crate::dom::webgl::webgluniformlocation::WebGLUniformLocation;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLProgram {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
id: WebGLProgramId,
|
||||
is_in_use: Cell<bool>,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
link_called: Cell<bool>,
|
||||
linked: Cell<bool>,
|
||||
link_generation: Cell<u64>,
|
||||
fragment_shader: MutNullableDom<WebGLShader>,
|
||||
vertex_shader: MutNullableDom<WebGLShader>,
|
||||
#[no_trace]
|
||||
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
|
||||
#[no_trace]
|
||||
active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>,
|
||||
#[no_trace]
|
||||
active_uniform_blocks: DomRefCell<Box<[ActiveUniformBlockInfo]>>,
|
||||
transform_feedback_varyings_length: Cell<i32>,
|
||||
transform_feedback_mode: Cell<i32>,
|
||||
}
|
||||
|
||||
impl WebGLProgram {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLProgramId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
id,
|
||||
is_in_use: Default::default(),
|
||||
marked_for_deletion: Default::default(),
|
||||
link_called: Default::default(),
|
||||
linked: Default::default(),
|
||||
link_generation: Default::default(),
|
||||
fragment_shader: Default::default(),
|
||||
vertex_shader: Default::default(),
|
||||
active_attribs: DomRefCell::new(vec![].into()),
|
||||
active_uniforms: DomRefCell::new(vec![].into()),
|
||||
active_uniform_blocks: DomRefCell::new(vec![].into()),
|
||||
transform_feedback_varyings_length: Default::default(),
|
||||
transform_feedback_mode: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_new(
|
||||
context: &WebGLRenderingContext,
|
||||
can_gc: CanGc,
|
||||
) -> Option<DomRoot<Self>> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateProgram(sender));
|
||||
receiver
|
||||
.recv()
|
||||
.unwrap()
|
||||
.map(|id| WebGLProgram::new(context, id, can_gc))
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLProgramId,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLProgram::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLProgram {
|
||||
pub(crate) fn id(&self) -> WebGLProgramId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// glDeleteProgram
|
||||
pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) {
|
||||
if self.marked_for_deletion.get() {
|
||||
return;
|
||||
}
|
||||
self.marked_for_deletion.set(true);
|
||||
let cmd = WebGLCommand::DeleteProgram(self.id);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
if self.is_deleted() {
|
||||
self.detach_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn in_use(&self, value: bool) {
|
||||
if self.is_in_use.get() == value {
|
||||
return;
|
||||
}
|
||||
self.is_in_use.set(value);
|
||||
if self.is_deleted() {
|
||||
self.detach_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
fn detach_shaders(&self) {
|
||||
assert!(self.is_deleted());
|
||||
if let Some(shader) = self.fragment_shader.get() {
|
||||
shader.decrement_attached_counter();
|
||||
self.fragment_shader.set(None);
|
||||
}
|
||||
if let Some(shader) = self.vertex_shader.get() {
|
||||
shader.decrement_attached_counter();
|
||||
self.vertex_shader.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_in_use(&self) -> bool {
|
||||
self.is_in_use.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_marked_for_deletion(&self) -> bool {
|
||||
self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.marked_for_deletion.get() && !self.is_in_use.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_linked(&self) -> bool {
|
||||
self.linked.get()
|
||||
}
|
||||
|
||||
/// glLinkProgram
|
||||
pub(crate) fn link(&self) -> WebGLResult<()> {
|
||||
self.linked.set(false);
|
||||
self.link_generation
|
||||
.set(self.link_generation.get().checked_add(1).unwrap());
|
||||
*self.active_attribs.borrow_mut() = Box::new([]);
|
||||
*self.active_uniforms.borrow_mut() = Box::new([]);
|
||||
*self.active_uniform_blocks.borrow_mut() = Box::new([]);
|
||||
|
||||
match self.fragment_shader.get() {
|
||||
Some(ref shader) if shader.successfully_compiled() => {},
|
||||
_ => return Ok(()), // callers use gl.LINK_STATUS to check link errors
|
||||
}
|
||||
|
||||
match self.vertex_shader.get() {
|
||||
Some(ref shader) if shader.successfully_compiled() => {},
|
||||
_ => return Ok(()), // callers use gl.LINK_STATUS to check link errors
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::LinkProgram(self.id, sender));
|
||||
let link_info = receiver.recv().unwrap();
|
||||
|
||||
{
|
||||
let mut used_locs = FnvHashSet::default();
|
||||
let mut used_names = FnvHashSet::default();
|
||||
for active_attrib in &*link_info.active_attribs {
|
||||
let Some(location) = active_attrib.location else {
|
||||
continue;
|
||||
};
|
||||
let columns = match active_attrib.type_ {
|
||||
constants::FLOAT_MAT2 => 2,
|
||||
constants::FLOAT_MAT3 => 3,
|
||||
constants::FLOAT_MAT4 => 4,
|
||||
_ => 1,
|
||||
};
|
||||
assert!(used_names.insert(&*active_attrib.name));
|
||||
for column in 0..columns {
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.31
|
||||
if !used_locs.insert(location + column) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
for active_uniform in &*link_info.active_uniforms {
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.41
|
||||
if !used_names.insert(&*active_uniform.base_name) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.linked.set(link_info.linked);
|
||||
self.link_called.set(true);
|
||||
self.transform_feedback_varyings_length
|
||||
.set(link_info.transform_feedback_length);
|
||||
self.transform_feedback_mode
|
||||
.set(link_info.transform_feedback_mode);
|
||||
*self.active_attribs.borrow_mut() = link_info.active_attribs;
|
||||
*self.active_uniforms.borrow_mut() = link_info.active_uniforms;
|
||||
*self.active_uniform_blocks.borrow_mut() = link_info.active_uniform_blocks;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn active_attribs(&self) -> Ref<'_, [ActiveAttribInfo]> {
|
||||
Ref::map(self.active_attribs.borrow(), |attribs| &**attribs)
|
||||
}
|
||||
|
||||
pub(crate) fn active_uniforms(&self) -> Ref<'_, [ActiveUniformInfo]> {
|
||||
Ref::map(self.active_uniforms.borrow(), |uniforms| &**uniforms)
|
||||
}
|
||||
|
||||
pub(crate) fn active_uniform_blocks(&self) -> Ref<'_, [ActiveUniformBlockInfo]> {
|
||||
Ref::map(self.active_uniform_blocks.borrow(), |blocks| &**blocks)
|
||||
}
|
||||
|
||||
/// glValidateProgram
|
||||
pub(crate) fn validate(&self) -> WebGLResult<()> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::ValidateProgram(self.id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glAttachShader
|
||||
pub(crate) fn attach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
|
||||
if self.is_deleted() || shader.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
let shader_slot = match shader.gl_type() {
|
||||
constants::FRAGMENT_SHADER => &self.fragment_shader,
|
||||
constants::VERTEX_SHADER => &self.vertex_shader,
|
||||
_ => {
|
||||
error!("detachShader: Unexpected shader type");
|
||||
return Err(WebGLError::InvalidValue);
|
||||
},
|
||||
};
|
||||
|
||||
if shader_slot.get().is_some() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
shader_slot.set(Some(shader));
|
||||
shader.increment_attached_counter();
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::AttachShader(self.id, shader.id()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glDetachShader
|
||||
pub(crate) fn detach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
let shader_slot = match shader.gl_type() {
|
||||
constants::FRAGMENT_SHADER => &self.fragment_shader,
|
||||
constants::VERTEX_SHADER => &self.vertex_shader,
|
||||
_ => return Err(WebGLError::InvalidValue),
|
||||
};
|
||||
|
||||
match shader_slot.get() {
|
||||
Some(ref attached_shader) if attached_shader.id() != shader.id() => {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
},
|
||||
None => return Err(WebGLError::InvalidOperation),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
shader_slot.set(None);
|
||||
shader.decrement_attached_counter();
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::DetachShader(self.id, shader.id()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glBindAttribLocation
|
||||
pub(crate) fn bind_attrib_location(&self, index: u32, name: DOMString) -> WebGLResult<()> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !validate_glsl_name(&name)? {
|
||||
return Ok(());
|
||||
}
|
||||
if name.starts_with("gl_") {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::BindAttribLocation(
|
||||
self.id,
|
||||
index,
|
||||
name.into(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_active_uniform(
|
||||
&self,
|
||||
index: u32,
|
||||
can_gc: CanGc,
|
||||
) -> WebGLResult<DomRoot<WebGLActiveInfo>> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
let uniforms = self.active_uniforms.borrow();
|
||||
let data = uniforms
|
||||
.get(index as usize)
|
||||
.ok_or(WebGLError::InvalidValue)?;
|
||||
Ok(WebGLActiveInfo::new(
|
||||
self.global().as_window(),
|
||||
data.size.unwrap_or(1),
|
||||
data.type_,
|
||||
data.name().into(),
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
/// glGetActiveAttrib
|
||||
pub(crate) fn get_active_attrib(
|
||||
&self,
|
||||
index: u32,
|
||||
can_gc: CanGc,
|
||||
) -> WebGLResult<DomRoot<WebGLActiveInfo>> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
let attribs = self.active_attribs.borrow();
|
||||
let data = attribs
|
||||
.get(index as usize)
|
||||
.ok_or(WebGLError::InvalidValue)?;
|
||||
Ok(WebGLActiveInfo::new(
|
||||
self.global().as_window(),
|
||||
data.size,
|
||||
data.type_,
|
||||
data.name.clone().into(),
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
/// glGetAttribLocation
|
||||
pub(crate) fn get_attrib_location(&self, name: DOMString) -> WebGLResult<i32> {
|
||||
if !self.is_linked() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !validate_glsl_name(&name)? {
|
||||
return Ok(-1);
|
||||
}
|
||||
if name.starts_with("gl_") {
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let location = self
|
||||
.active_attribs
|
||||
.borrow()
|
||||
.iter()
|
||||
.find(|attrib| attrib.name == *name)
|
||||
.and_then(|attrib| attrib.location.map(|l| l as i32))
|
||||
.unwrap_or(-1);
|
||||
Ok(location)
|
||||
}
|
||||
|
||||
/// glGetFragDataLocation
|
||||
pub(crate) fn get_frag_data_location(&self, name: DOMString) -> WebGLResult<i32> {
|
||||
if !self.is_linked() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !validate_glsl_name(&name)? {
|
||||
return Ok(-1);
|
||||
}
|
||||
if name.starts_with("gl_") {
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetFragDataLocation(
|
||||
self.id,
|
||||
name.into(),
|
||||
sender,
|
||||
));
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
/// glGetUniformLocation
|
||||
pub(crate) fn get_uniform_location(
|
||||
&self,
|
||||
name: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> WebGLResult<Option<DomRoot<WebGLUniformLocation>>> {
|
||||
if !self.is_linked() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !validate_glsl_name(&name)? {
|
||||
return Ok(None);
|
||||
}
|
||||
if name.starts_with("gl_") {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let (size, type_) = {
|
||||
let (base_name, array_index) = match parse_uniform_name(&name) {
|
||||
Some((name, index)) if index.is_none_or(|i| i >= 0) => (name, index),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let uniforms = self.active_uniforms.borrow();
|
||||
match uniforms
|
||||
.iter()
|
||||
.find(|attrib| &*attrib.base_name == base_name)
|
||||
{
|
||||
Some(uniform) if array_index.is_none() || array_index < uniform.size => (
|
||||
uniform
|
||||
.size
|
||||
.map(|size| size - array_index.unwrap_or_default()),
|
||||
uniform.type_,
|
||||
),
|
||||
_ => return Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetUniformLocation(
|
||||
self.id,
|
||||
name.into(),
|
||||
sender,
|
||||
));
|
||||
let location = receiver.recv().unwrap();
|
||||
let context_id = self.upcast::<WebGLObject>().context().context_id();
|
||||
|
||||
Ok(Some(WebGLUniformLocation::new(
|
||||
self.global().as_window(),
|
||||
location,
|
||||
context_id,
|
||||
self.id,
|
||||
self.link_generation.get(),
|
||||
size,
|
||||
type_,
|
||||
can_gc,
|
||||
)))
|
||||
}
|
||||
|
||||
pub(crate) fn get_uniform_block_index(&self, name: DOMString) -> WebGLResult<u32> {
|
||||
if !self.link_called.get() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !validate_glsl_name(&name)? {
|
||||
return Ok(constants2::INVALID_INDEX);
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetUniformBlockIndex(
|
||||
self.id,
|
||||
name.into(),
|
||||
sender,
|
||||
));
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn get_uniform_indices(&self, names: Vec<DOMString>) -> WebGLResult<Vec<u32>> {
|
||||
if !self.link_called.get() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
let validation_errors = names
|
||||
.iter()
|
||||
.map(|name| validate_glsl_name(name))
|
||||
.collect::<Vec<_>>();
|
||||
let first_validation_error = validation_errors.iter().find(|result| result.is_err());
|
||||
if let Some(error) = first_validation_error {
|
||||
return Err(error.unwrap_err());
|
||||
}
|
||||
|
||||
let names = names
|
||||
.iter()
|
||||
.map(|name| name.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetUniformIndices(self.id, names, sender));
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn get_active_uniforms(
|
||||
&self,
|
||||
indices: Vec<u32>,
|
||||
pname: u32,
|
||||
) -> WebGLResult<Vec<i32>> {
|
||||
if !self.is_linked() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
match pname {
|
||||
constants2::UNIFORM_TYPE |
|
||||
constants2::UNIFORM_SIZE |
|
||||
constants2::UNIFORM_BLOCK_INDEX |
|
||||
constants2::UNIFORM_OFFSET |
|
||||
constants2::UNIFORM_ARRAY_STRIDE |
|
||||
constants2::UNIFORM_MATRIX_STRIDE |
|
||||
constants2::UNIFORM_IS_ROW_MAJOR => {},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
}
|
||||
|
||||
if indices.len() > self.active_uniforms.borrow().len() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetActiveUniforms(
|
||||
self.id, indices, pname, sender,
|
||||
));
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn get_active_uniform_block_parameter(
|
||||
&self,
|
||||
block_index: u32,
|
||||
pname: u32,
|
||||
) -> WebGLResult<Vec<i32>> {
|
||||
if !self.link_called.get() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if block_index as usize >= self.active_uniform_blocks.borrow().len() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
match pname {
|
||||
constants2::UNIFORM_BLOCK_BINDING |
|
||||
constants2::UNIFORM_BLOCK_DATA_SIZE |
|
||||
constants2::UNIFORM_BLOCK_ACTIVE_UNIFORMS |
|
||||
constants2::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES |
|
||||
constants2::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
|
||||
constants2::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>().context().send_command(
|
||||
WebGLCommand::GetActiveUniformBlockParameter(self.id, block_index, pname, sender),
|
||||
);
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn get_active_uniform_block_name(&self, block_index: u32) -> WebGLResult<String> {
|
||||
if !self.link_called.get() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if block_index as usize >= self.active_uniform_blocks.borrow().len() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>().context().send_command(
|
||||
WebGLCommand::GetActiveUniformBlockName(self.id, block_index, sender),
|
||||
);
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn bind_uniform_block(
|
||||
&self,
|
||||
block_index: u32,
|
||||
block_binding: u32,
|
||||
) -> WebGLResult<()> {
|
||||
if block_index as usize >= self.active_uniform_blocks.borrow().len() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
|
||||
let mut active_uniforms = self.active_uniforms.borrow_mut();
|
||||
if active_uniforms.len() > block_binding as usize {
|
||||
active_uniforms[block_binding as usize].bind_index = Some(block_binding);
|
||||
}
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::UniformBlockBinding(
|
||||
self.id,
|
||||
block_index,
|
||||
block_binding,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glGetProgramInfoLog
|
||||
pub(crate) fn get_info_log(&self) -> WebGLResult<String> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
if self.link_called.get() {
|
||||
let shaders_compiled = match (self.fragment_shader.get(), self.vertex_shader.get()) {
|
||||
(Some(fs), Some(vs)) => fs.successfully_compiled() && vs.successfully_compiled(),
|
||||
_ => false,
|
||||
};
|
||||
if !shaders_compiled {
|
||||
return Ok("One or more shaders failed to compile".to_string());
|
||||
}
|
||||
}
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GetProgramInfoLog(self.id, sender));
|
||||
Ok(receiver.recv().unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn attached_shaders(&self) -> WebGLResult<Vec<DomRoot<WebGLShader>>> {
|
||||
if self.marked_for_deletion.get() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
Ok(
|
||||
match (self.vertex_shader.get(), self.fragment_shader.get()) {
|
||||
(Some(vertex_shader), Some(fragment_shader)) => {
|
||||
vec![vertex_shader, fragment_shader]
|
||||
},
|
||||
(Some(shader), None) | (None, Some(shader)) => vec![shader],
|
||||
(None, None) => vec![],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn link_generation(&self) -> u64 {
|
||||
self.link_generation.get()
|
||||
}
|
||||
|
||||
pub(crate) fn transform_feedback_varyings_length(&self) -> i32 {
|
||||
self.transform_feedback_varyings_length.get()
|
||||
}
|
||||
|
||||
pub(crate) fn transform_feedback_buffer_mode(&self) -> i32 {
|
||||
self.transform_feedback_mode.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLProgram {
|
||||
fn drop(&mut self) {
|
||||
self.in_use(false);
|
||||
self.mark_for_deletion(Operation::Fallible);
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_glsl_name(name: &str) -> WebGLResult<bool> {
|
||||
if name.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
for c in name.chars() {
|
||||
validate_glsl_char(c)?;
|
||||
}
|
||||
if name.starts_with("webgl_") || name.starts_with("_webgl_") {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn validate_glsl_char(c: char) -> WebGLResult<()> {
|
||||
match c {
|
||||
'a'..='z' |
|
||||
'A'..='Z' |
|
||||
'0'..='9' |
|
||||
' ' |
|
||||
'\t' |
|
||||
'\u{11}' |
|
||||
'\u{12}' |
|
||||
'\r' |
|
||||
'\n' |
|
||||
'_' |
|
||||
'.' |
|
||||
'+' |
|
||||
'-' |
|
||||
'/' |
|
||||
'*' |
|
||||
'%' |
|
||||
'<' |
|
||||
'>' |
|
||||
'[' |
|
||||
']' |
|
||||
'(' |
|
||||
')' |
|
||||
'{' |
|
||||
'}' |
|
||||
'^' |
|
||||
'|' |
|
||||
'&' |
|
||||
'~' |
|
||||
'=' |
|
||||
'!' |
|
||||
':' |
|
||||
';' |
|
||||
',' |
|
||||
'?' => Ok(()),
|
||||
_ => Err(WebGLError::InvalidValue),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_uniform_name(name: &str) -> Option<(&str, Option<i32>)> {
|
||||
if !name.ends_with(']') {
|
||||
return Some((name, None));
|
||||
}
|
||||
let bracket_pos = name[..name.len() - 1].rfind('[')?;
|
||||
let index = name[(bracket_pos + 1)..(name.len() - 1)]
|
||||
.parse::<i32>()
|
||||
.ok()?;
|
||||
Some((&name[..bracket_pos], Some(index)))
|
||||
}
|
||||
|
||||
pub(crate) const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256;
|
192
components/script/dom/webgl/webglquery.rs
Normal file
192
components/script/dom/webgl/webglquery.rs
Normal file
|
@ -0,0 +1,192 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::WebGLError::*;
|
||||
use canvas_traits::webgl::{WebGLCommand, WebGLQueryId, webgl_channel};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLQuery {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
gl_id: WebGLQueryId,
|
||||
gl_target: Cell<Option<u32>>,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
query_result_available: Cell<Option<u32>>,
|
||||
query_result: Cell<u32>,
|
||||
}
|
||||
|
||||
impl WebGLQuery {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLQueryId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
gl_id: id,
|
||||
gl_target: Cell::new(None),
|
||||
marked_for_deletion: Cell::new(false),
|
||||
query_result_available: Cell::new(None),
|
||||
query_result: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GenerateQuery(sender));
|
||||
let id = receiver.recv().unwrap();
|
||||
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn begin(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
target: u32,
|
||||
) -> Result<(), canvas_traits::webgl::WebGLError> {
|
||||
if self.marked_for_deletion.get() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
if let Some(current_target) = self.gl_target.get() {
|
||||
if current_target != target {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
}
|
||||
match target {
|
||||
constants::ANY_SAMPLES_PASSED |
|
||||
constants::ANY_SAMPLES_PASSED_CONSERVATIVE |
|
||||
constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => (),
|
||||
_ => return Err(InvalidEnum),
|
||||
}
|
||||
self.gl_target.set(Some(target));
|
||||
|
||||
context.send_command(WebGLCommand::BeginQuery(target, self.gl_id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn end(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
target: u32,
|
||||
) -> Result<(), canvas_traits::webgl::WebGLError> {
|
||||
if self.marked_for_deletion.get() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
if let Some(current_target) = self.gl_target.get() {
|
||||
if current_target != target {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
}
|
||||
match target {
|
||||
constants::ANY_SAMPLES_PASSED |
|
||||
constants::ANY_SAMPLES_PASSED_CONSERVATIVE |
|
||||
constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => (),
|
||||
_ => return Err(InvalidEnum),
|
||||
}
|
||||
context.send_command(WebGLCommand::EndQuery(target));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if !self.marked_for_deletion.get() {
|
||||
self.marked_for_deletion.set(true);
|
||||
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
let command = WebGLCommand::DeleteQuery(self.gl_id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(command),
|
||||
Operation::Infallible => context.send_command(command),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_valid(&self) -> bool {
|
||||
!self.marked_for_deletion.get() && self.target().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn target(&self) -> Option<u32> {
|
||||
self.gl_target.get()
|
||||
}
|
||||
|
||||
fn update_results(&self, context: &WebGLRenderingContext) {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GetQueryState(
|
||||
sender,
|
||||
self.gl_id,
|
||||
constants::QUERY_RESULT_AVAILABLE,
|
||||
));
|
||||
let is_available = receiver.recv().unwrap();
|
||||
if is_available == 0 {
|
||||
self.query_result_available.set(None);
|
||||
return;
|
||||
}
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GetQueryState(
|
||||
sender,
|
||||
self.gl_id,
|
||||
constants::QUERY_RESULT,
|
||||
));
|
||||
|
||||
self.query_result.set(receiver.recv().unwrap());
|
||||
self.query_result_available.set(Some(is_available));
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(crate) fn get_parameter(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
pname: u32,
|
||||
) -> Result<u32, canvas_traits::webgl::WebGLError> {
|
||||
if !self.is_valid() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
match pname {
|
||||
constants::QUERY_RESULT |
|
||||
constants::QUERY_RESULT_AVAILABLE => {},
|
||||
_ => return Err(InvalidEnum),
|
||||
}
|
||||
|
||||
if self.query_result_available.get().is_none() {
|
||||
self.query_result_available.set(Some(0));
|
||||
|
||||
let this = Trusted::new(self);
|
||||
let context = Trusted::new(context);
|
||||
let task = task!(request_query_state: move || {
|
||||
let this = this.root();
|
||||
let context = context.root();
|
||||
this.update_results(&context);
|
||||
});
|
||||
|
||||
self.global()
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task);
|
||||
}
|
||||
|
||||
match pname {
|
||||
constants::QUERY_RESULT => Ok(self.query_result.get()),
|
||||
constants::QUERY_RESULT_AVAILABLE => Ok(self.query_result_available.get().unwrap()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLQuery {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
290
components/script/dom/webgl/webglrenderbuffer.rs
Normal file
290
components/script/dom/webgl/webglrenderbuffer.rs
Normal file
|
@ -0,0 +1,290 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{
|
||||
GlType, InternalFormatIntVec, WebGLCommand, WebGLError, WebGLRenderbufferId, WebGLResult,
|
||||
WebGLVersion, webgl_channel,
|
||||
};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EXTColorBufferHalfFloatBinding::EXTColorBufferHalfFloatConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WEBGLColorBufferFloatBinding::WEBGLColorBufferFloatConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::webgl::webglframebuffer::WebGLFramebuffer;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLRenderbuffer {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
id: WebGLRenderbufferId,
|
||||
ever_bound: Cell<bool>,
|
||||
is_deleted: Cell<bool>,
|
||||
size: Cell<Option<(i32, i32)>>,
|
||||
internal_format: Cell<Option<u32>>,
|
||||
is_initialized: Cell<bool>,
|
||||
attached_framebuffer: MutNullableDom<WebGLFramebuffer>,
|
||||
}
|
||||
|
||||
impl WebGLRenderbuffer {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLRenderbufferId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
id,
|
||||
ever_bound: Cell::new(false),
|
||||
is_deleted: Cell::new(false),
|
||||
internal_format: Cell::new(None),
|
||||
size: Cell::new(None),
|
||||
is_initialized: Cell::new(false),
|
||||
attached_framebuffer: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateRenderbuffer(sender));
|
||||
receiver
|
||||
.recv()
|
||||
.unwrap()
|
||||
.map(|id| WebGLRenderbuffer::new(context, id, CanGc::note()))
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLRenderbufferId,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLRenderbuffer::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLRenderbuffer {
|
||||
pub(crate) fn id(&self) -> WebGLRenderbufferId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn size(&self) -> Option<(i32, i32)> {
|
||||
self.size.get()
|
||||
}
|
||||
|
||||
pub(crate) fn internal_format(&self) -> u32 {
|
||||
self.internal_format.get().unwrap_or(constants::RGBA4)
|
||||
}
|
||||
|
||||
pub(crate) fn mark_initialized(&self) {
|
||||
self.is_initialized.set(true);
|
||||
}
|
||||
|
||||
pub(crate) fn is_initialized(&self) -> bool {
|
||||
self.is_initialized.get()
|
||||
}
|
||||
|
||||
pub(crate) fn bind(&self, target: u32) {
|
||||
self.ever_bound.set(true);
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::BindRenderbuffer(target, Some(self.id)));
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if !self.is_deleted.get() {
|
||||
self.is_deleted.set(true);
|
||||
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
|
||||
/*
|
||||
If a renderbuffer object is deleted while its image is attached to one or more
|
||||
attachment points in a currently bound framebuffer object, then it is as if
|
||||
FramebufferRenderbuffer had been called, with a renderbuffer of zero, for each
|
||||
attachment point to which this image was attached in that framebuffer object.
|
||||
In other words,the renderbuffer image is first detached from all attachment points
|
||||
in that frame-buffer object.
|
||||
- GLES 3.0, 4.4.2.3, "Attaching Renderbuffer Images to a Framebuffer"
|
||||
*/
|
||||
if let Some(fb) = context.get_draw_framebuffer_slot().get() {
|
||||
let _ = fb.detach_renderbuffer(self);
|
||||
}
|
||||
if let Some(fb) = context.get_read_framebuffer_slot().get() {
|
||||
let _ = fb.detach_renderbuffer(self);
|
||||
}
|
||||
|
||||
let cmd = WebGLCommand::DeleteRenderbuffer(self.id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.is_deleted.get()
|
||||
}
|
||||
|
||||
pub(crate) fn ever_bound(&self) -> bool {
|
||||
self.ever_bound.get()
|
||||
}
|
||||
|
||||
pub(crate) fn storage(
|
||||
&self,
|
||||
api_type: GlType,
|
||||
sample_count: i32,
|
||||
internal_format: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> WebGLResult<()> {
|
||||
let is_gles = api_type == GlType::Gles;
|
||||
let webgl_version = self.upcast().context().webgl_version();
|
||||
|
||||
// Validate the internal_format, and save it for completeness
|
||||
// validation.
|
||||
let actual_format = match internal_format {
|
||||
constants::RGBA4 | constants::DEPTH_COMPONENT16 | constants::STENCIL_INDEX8 => {
|
||||
internal_format
|
||||
},
|
||||
constants::R8 |
|
||||
constants::R8UI |
|
||||
constants::R8I |
|
||||
constants::R16UI |
|
||||
constants::R16I |
|
||||
constants::R32UI |
|
||||
constants::R32I |
|
||||
constants::RG8 |
|
||||
constants::RG8UI |
|
||||
constants::RG8I |
|
||||
constants::RG16UI |
|
||||
constants::RG16I |
|
||||
constants::RG32UI |
|
||||
constants::RG32I |
|
||||
constants::RGB8 |
|
||||
constants::RGBA8 |
|
||||
constants::SRGB8_ALPHA8 |
|
||||
constants::RGB10_A2 |
|
||||
constants::RGBA8UI |
|
||||
constants::RGBA8I |
|
||||
constants::RGB10_A2UI |
|
||||
constants::RGBA16UI |
|
||||
constants::RGBA16I |
|
||||
constants::RGBA32I |
|
||||
constants::RGBA32UI |
|
||||
constants::DEPTH_COMPONENT24 |
|
||||
constants::DEPTH_COMPONENT32F |
|
||||
constants::DEPTH24_STENCIL8 |
|
||||
constants::DEPTH32F_STENCIL8 => match webgl_version {
|
||||
WebGLVersion::WebGL1 => return Err(WebGLError::InvalidEnum),
|
||||
_ => internal_format,
|
||||
},
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.8
|
||||
constants::DEPTH_STENCIL => constants::DEPTH24_STENCIL8,
|
||||
constants::RGB5_A1 => {
|
||||
// 16-bit RGBA formats are not supported on desktop GL.
|
||||
if is_gles {
|
||||
constants::RGB5_A1
|
||||
} else {
|
||||
constants::RGBA8
|
||||
}
|
||||
},
|
||||
constants::RGB565 => {
|
||||
// RGB565 is not supported on desktop GL.
|
||||
if is_gles {
|
||||
constants::RGB565
|
||||
} else {
|
||||
constants::RGB8
|
||||
}
|
||||
},
|
||||
EXTColorBufferHalfFloatConstants::RGBA16F_EXT |
|
||||
EXTColorBufferHalfFloatConstants::RGB16F_EXT => {
|
||||
if !self
|
||||
.upcast()
|
||||
.context()
|
||||
.extension_manager()
|
||||
.is_half_float_buffer_renderable()
|
||||
{
|
||||
return Err(WebGLError::InvalidEnum);
|
||||
}
|
||||
internal_format
|
||||
},
|
||||
WEBGLColorBufferFloatConstants::RGBA32F_EXT => {
|
||||
if !self
|
||||
.upcast()
|
||||
.context()
|
||||
.extension_manager()
|
||||
.is_float_buffer_renderable()
|
||||
{
|
||||
return Err(WebGLError::InvalidEnum);
|
||||
}
|
||||
internal_format
|
||||
},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
|
||||
if webgl_version != WebGLVersion::WebGL1 {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.upcast::<WebGLObject>().context().send_command(
|
||||
WebGLCommand::GetInternalFormatIntVec(
|
||||
constants::RENDERBUFFER,
|
||||
internal_format,
|
||||
InternalFormatIntVec::Samples,
|
||||
sender,
|
||||
),
|
||||
);
|
||||
let samples = receiver.recv().unwrap();
|
||||
if sample_count < 0 || sample_count > samples.first().cloned().unwrap_or(0) {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
}
|
||||
|
||||
self.internal_format.set(Some(internal_format));
|
||||
self.is_initialized.set(false);
|
||||
|
||||
if let Some(fb) = self.attached_framebuffer.get() {
|
||||
fb.update_status();
|
||||
}
|
||||
|
||||
let command = match sample_count {
|
||||
0 => WebGLCommand::RenderbufferStorage(
|
||||
constants::RENDERBUFFER,
|
||||
actual_format,
|
||||
width,
|
||||
height,
|
||||
),
|
||||
_ => WebGLCommand::RenderbufferStorageMultisample(
|
||||
constants::RENDERBUFFER,
|
||||
sample_count,
|
||||
actual_format,
|
||||
width,
|
||||
height,
|
||||
),
|
||||
};
|
||||
self.upcast::<WebGLObject>().context().send_command(command);
|
||||
|
||||
self.size.set(Some((width, height)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn attach_to_framebuffer(&self, fb: &WebGLFramebuffer) {
|
||||
self.attached_framebuffer.set(Some(fb));
|
||||
}
|
||||
|
||||
pub(crate) fn detach_from_framebuffer(&self) {
|
||||
self.attached_framebuffer.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLRenderbuffer {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
5265
components/script/dom/webgl/webglrenderingcontext.rs
Normal file
5265
components/script/dom/webgl/webglrenderingcontext.rs
Normal file
File diff suppressed because it is too large
Load diff
189
components/script/dom/webgl/webglsampler.rs
Normal file
189
components/script/dom/webgl/webglsampler.rs
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::WebGLError::*;
|
||||
use canvas_traits::webgl::{WebGLCommand, WebGLSamplerId, webgl_channel};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLSampler {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
gl_id: WebGLSamplerId,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum WebGLSamplerValue {
|
||||
Float(f32),
|
||||
GLenum(u32),
|
||||
}
|
||||
|
||||
fn validate_params(pname: u32, value: WebGLSamplerValue) -> bool {
|
||||
match value {
|
||||
WebGLSamplerValue::GLenum(value) => {
|
||||
let allowed_values = match pname {
|
||||
constants::TEXTURE_MIN_FILTER => &[
|
||||
constants::NEAREST,
|
||||
constants::LINEAR,
|
||||
constants::NEAREST_MIPMAP_NEAREST,
|
||||
constants::LINEAR_MIPMAP_NEAREST,
|
||||
constants::NEAREST_MIPMAP_LINEAR,
|
||||
constants::LINEAR_MIPMAP_LINEAR,
|
||||
][..],
|
||||
constants::TEXTURE_MAG_FILTER => &[constants::NEAREST, constants::LINEAR][..],
|
||||
constants::TEXTURE_WRAP_R |
|
||||
constants::TEXTURE_WRAP_S |
|
||||
constants::TEXTURE_WRAP_T => &[
|
||||
constants::CLAMP_TO_EDGE,
|
||||
constants::MIRRORED_REPEAT,
|
||||
constants::REPEAT,
|
||||
][..],
|
||||
constants::TEXTURE_COMPARE_MODE => {
|
||||
&[constants::NONE, constants::COMPARE_REF_TO_TEXTURE][..]
|
||||
},
|
||||
constants::TEXTURE_COMPARE_FUNC => &[
|
||||
constants::LEQUAL,
|
||||
constants::GEQUAL,
|
||||
constants::LESS,
|
||||
constants::GREATER,
|
||||
constants::EQUAL,
|
||||
constants::NOTEQUAL,
|
||||
constants::ALWAYS,
|
||||
constants::NEVER,
|
||||
][..],
|
||||
_ => &[][..],
|
||||
};
|
||||
allowed_values.contains(&value)
|
||||
},
|
||||
WebGLSamplerValue::Float(_) => matches!(
|
||||
pname,
|
||||
constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLSampler {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLSamplerId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
gl_id: id,
|
||||
marked_for_deletion: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GenerateSampler(sender));
|
||||
let id = receiver.recv().unwrap();
|
||||
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if !self.marked_for_deletion.get() {
|
||||
self.marked_for_deletion.set(true);
|
||||
|
||||
let command = WebGLCommand::DeleteSampler(self.gl_id);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(command),
|
||||
Operation::Infallible => context.send_command(command),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_valid(&self) -> bool {
|
||||
!self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn bind(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
unit: u32,
|
||||
) -> Result<(), canvas_traits::webgl::WebGLError> {
|
||||
if !self.is_valid() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
context.send_command(WebGLCommand::BindSampler(unit, self.gl_id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_parameter(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
pname: u32,
|
||||
value: WebGLSamplerValue,
|
||||
) -> Result<(), canvas_traits::webgl::WebGLError> {
|
||||
if !self.is_valid() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
if !validate_params(pname, value) {
|
||||
return Err(InvalidEnum);
|
||||
}
|
||||
let command = match value {
|
||||
WebGLSamplerValue::GLenum(value) => {
|
||||
WebGLCommand::SetSamplerParameterInt(self.gl_id, pname, value as i32)
|
||||
},
|
||||
WebGLSamplerValue::Float(value) => {
|
||||
WebGLCommand::SetSamplerParameterFloat(self.gl_id, pname, value)
|
||||
},
|
||||
};
|
||||
context.send_command(command);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_parameter(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
pname: u32,
|
||||
) -> Result<WebGLSamplerValue, canvas_traits::webgl::WebGLError> {
|
||||
if !self.is_valid() {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
match pname {
|
||||
constants::TEXTURE_MIN_FILTER |
|
||||
constants::TEXTURE_MAG_FILTER |
|
||||
constants::TEXTURE_WRAP_R |
|
||||
constants::TEXTURE_WRAP_S |
|
||||
constants::TEXTURE_WRAP_T |
|
||||
constants::TEXTURE_COMPARE_FUNC |
|
||||
constants::TEXTURE_COMPARE_MODE => {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GetSamplerParameterInt(
|
||||
self.gl_id, pname, sender,
|
||||
));
|
||||
Ok(WebGLSamplerValue::GLenum(receiver.recv().unwrap() as u32))
|
||||
},
|
||||
constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD => {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GetSamplerParameterFloat(
|
||||
self.gl_id, pname, sender,
|
||||
));
|
||||
Ok(WebGLSamplerValue::Float(receiver.recv().unwrap()))
|
||||
},
|
||||
_ => Err(InvalidEnum),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLSampler {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
293
components/script/dom/webgl/webglshader.rs
Normal file
293
components/script/dom/webgl/webglshader.rs
Normal file
|
@ -0,0 +1,293 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use std::cell::Cell;
|
||||
use std::os::raw::c_int;
|
||||
use std::sync::Once;
|
||||
|
||||
use canvas_traits::webgl::{
|
||||
GLLimits, GlType, WebGLCommand, WebGLError, WebGLResult, WebGLSLVersion, WebGLShaderId,
|
||||
WebGLVersion, webgl_channel,
|
||||
};
|
||||
use dom_struct::dom_struct;
|
||||
use mozangle::shaders::{BuiltInResources, CompileOptions, Output, ShaderValidator};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::webgl::extensions::WebGLExtensions;
|
||||
use crate::dom::webgl::extensions::extfragdepth::EXTFragDepth;
|
||||
use crate::dom::webgl::extensions::extshadertexturelod::EXTShaderTextureLod;
|
||||
use crate::dom::webgl::extensions::oesstandardderivatives::OESStandardDerivatives;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
pub(crate) enum ShaderCompilationStatus {
|
||||
NotCompiled,
|
||||
Succeeded,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLShader {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
id: WebGLShaderId,
|
||||
gl_type: u32,
|
||||
source: DomRefCell<DOMString>,
|
||||
info_log: DomRefCell<DOMString>,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
attached_counter: Cell<u32>,
|
||||
compilation_status: Cell<ShaderCompilationStatus>,
|
||||
}
|
||||
|
||||
static GLSLANG_INITIALIZATION: Once = Once::new();
|
||||
|
||||
impl WebGLShader {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: WebGLShaderId, shader_type: u32) -> Self {
|
||||
GLSLANG_INITIALIZATION.call_once(|| ::mozangle::shaders::initialize().unwrap());
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
id,
|
||||
gl_type: shader_type,
|
||||
source: Default::default(),
|
||||
info_log: Default::default(),
|
||||
marked_for_deletion: Cell::new(false),
|
||||
attached_counter: Cell::new(0),
|
||||
compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_new(
|
||||
context: &WebGLRenderingContext,
|
||||
shader_type: u32,
|
||||
) -> Option<DomRoot<Self>> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateShader(shader_type, sender));
|
||||
receiver
|
||||
.recv()
|
||||
.unwrap()
|
||||
.map(|id| WebGLShader::new(context, id, shader_type, CanGc::note()))
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLShaderId,
|
||||
shader_type: u32,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLShader::new_inherited(context, id, shader_type)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLShader {
|
||||
pub(crate) fn id(&self) -> WebGLShaderId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn gl_type(&self) -> u32 {
|
||||
self.gl_type
|
||||
}
|
||||
|
||||
/// glCompileShader
|
||||
pub(crate) fn compile(
|
||||
&self,
|
||||
api_type: GlType,
|
||||
webgl_version: WebGLVersion,
|
||||
glsl_version: WebGLSLVersion,
|
||||
limits: &GLLimits,
|
||||
ext: &WebGLExtensions,
|
||||
) -> WebGLResult<()> {
|
||||
if self.marked_for_deletion.get() && !self.is_attached() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
if self.compilation_status.get() != ShaderCompilationStatus::NotCompiled {
|
||||
debug!("Compiling already compiled shader {}", self.id);
|
||||
}
|
||||
|
||||
let source = self.source.borrow();
|
||||
|
||||
let mut params = BuiltInResources {
|
||||
MaxVertexAttribs: limits.max_vertex_attribs as c_int,
|
||||
MaxVertexUniformVectors: limits.max_vertex_uniform_vectors as c_int,
|
||||
MaxVertexTextureImageUnits: limits.max_vertex_texture_image_units as c_int,
|
||||
MaxCombinedTextureImageUnits: limits.max_combined_texture_image_units as c_int,
|
||||
MaxTextureImageUnits: limits.max_texture_image_units as c_int,
|
||||
MaxFragmentUniformVectors: limits.max_fragment_uniform_vectors as c_int,
|
||||
|
||||
MaxVertexOutputVectors: limits.max_vertex_output_vectors as c_int,
|
||||
MaxFragmentInputVectors: limits.max_fragment_input_vectors as c_int,
|
||||
MaxVaryingVectors: limits.max_varying_vectors as c_int,
|
||||
|
||||
OES_standard_derivatives: ext.is_enabled::<OESStandardDerivatives>() as c_int,
|
||||
EXT_shader_texture_lod: ext.is_enabled::<EXTShaderTextureLod>() as c_int,
|
||||
EXT_frag_depth: ext.is_enabled::<EXTFragDepth>() as c_int,
|
||||
|
||||
FragmentPrecisionHigh: 1,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if webgl_version == WebGLVersion::WebGL2 {
|
||||
params.MinProgramTexelOffset = limits.min_program_texel_offset as c_int;
|
||||
params.MaxProgramTexelOffset = limits.max_program_texel_offset as c_int;
|
||||
params.MaxDrawBuffers = limits.max_draw_buffers as c_int;
|
||||
}
|
||||
|
||||
let validator = match webgl_version {
|
||||
WebGLVersion::WebGL1 => {
|
||||
let output_format = if api_type == GlType::Gles {
|
||||
Output::Essl
|
||||
} else {
|
||||
Output::Glsl
|
||||
};
|
||||
ShaderValidator::for_webgl(self.gl_type, output_format, ¶ms).unwrap()
|
||||
},
|
||||
WebGLVersion::WebGL2 => {
|
||||
let output_format = if api_type == GlType::Gles {
|
||||
Output::Essl
|
||||
} else {
|
||||
match (glsl_version.major, glsl_version.minor) {
|
||||
(1, 30) => Output::Glsl130,
|
||||
(1, 40) => Output::Glsl140,
|
||||
(1, 50) => Output::Glsl150Core,
|
||||
(3, 30) => Output::Glsl330Core,
|
||||
(4, 0) => Output::Glsl400Core,
|
||||
(4, 10) => Output::Glsl410Core,
|
||||
(4, 20) => Output::Glsl420Core,
|
||||
(4, 30) => Output::Glsl430Core,
|
||||
(4, 40) => Output::Glsl440Core,
|
||||
(4, _) => Output::Glsl450Core,
|
||||
_ => Output::Glsl140,
|
||||
}
|
||||
};
|
||||
ShaderValidator::for_webgl2(self.gl_type, output_format, ¶ms).unwrap()
|
||||
},
|
||||
};
|
||||
|
||||
// Replicating
|
||||
// https://searchfox.org/mozilla-esr115/rev/f1fb0868dc63b89ccf9eea157960d1ec27fb55a2/dom/canvas/WebGLShaderValidator.cpp#29
|
||||
let mut options = CompileOptions::mozangle();
|
||||
options.set_variables(1);
|
||||
options.set_enforcePackingRestrictions(1);
|
||||
options.set_objectCode(1);
|
||||
options.set_initGLPosition(1);
|
||||
options.set_initializeUninitializedLocals(1);
|
||||
options.set_initOutputVariables(1);
|
||||
|
||||
options.set_limitExpressionComplexity(1);
|
||||
options.set_limitCallStackDepth(1);
|
||||
|
||||
if cfg!(target_os = "macos") {
|
||||
options.set_removeInvariantAndCentroidForESSL3(1);
|
||||
|
||||
// Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
|
||||
// https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
|
||||
options.set_unfoldShortCircuit(1);
|
||||
// Work around that Mac drivers handle struct scopes incorrectly.
|
||||
options.set_regenerateStructNames(1);
|
||||
// TODO: Only apply this workaround to Intel hardware
|
||||
// Work around that Intel drivers on Mac OSX handle for-loop incorrectly.
|
||||
options.set_addAndTrueToLoopCondition(1);
|
||||
options.set_rewriteTexelFetchOffsetToTexelFetch(1);
|
||||
} else {
|
||||
// We want to do this everywhere, but to do this on Mac, we need
|
||||
// to do it only on Mac OSX > 10.6 as this causes the shader
|
||||
// compiler in 10.6 to crash
|
||||
options.set_clampIndirectArrayBounds(1);
|
||||
}
|
||||
|
||||
match validator.compile(&[&source], options) {
|
||||
Ok(()) => {
|
||||
let translated_source = validator.object_code();
|
||||
debug!("Shader translated: {}", translated_source);
|
||||
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
|
||||
// will succeed.
|
||||
// It could be interesting to retrieve the info log from the paint thread though
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::CompileShader(self.id, translated_source));
|
||||
self.compilation_status
|
||||
.set(ShaderCompilationStatus::Succeeded);
|
||||
},
|
||||
Err(error) => {
|
||||
self.compilation_status.set(ShaderCompilationStatus::Failed);
|
||||
debug!("Shader {} compilation failed: {}", self.id, error);
|
||||
},
|
||||
}
|
||||
|
||||
*self.info_log.borrow_mut() = validator.info_log().into();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mark this shader as deleted (if it wasn't previously)
|
||||
/// and delete it as if calling glDeleteShader.
|
||||
/// Currently does not check if shader is attached
|
||||
pub(crate) fn mark_for_deletion(&self, operation_fallibility: Operation) {
|
||||
if !self.marked_for_deletion.get() {
|
||||
self.marked_for_deletion.set(true);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
let cmd = WebGLCommand::DeleteShader(self.id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_marked_for_deletion(&self) -> bool {
|
||||
self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.marked_for_deletion.get() && !self.is_attached()
|
||||
}
|
||||
|
||||
pub(crate) fn is_attached(&self) -> bool {
|
||||
self.attached_counter.get() > 0
|
||||
}
|
||||
|
||||
pub(crate) fn increment_attached_counter(&self) {
|
||||
self.attached_counter.set(self.attached_counter.get() + 1);
|
||||
}
|
||||
|
||||
pub(crate) fn decrement_attached_counter(&self) {
|
||||
assert!(self.attached_counter.get() > 0);
|
||||
self.attached_counter.set(self.attached_counter.get() - 1);
|
||||
}
|
||||
|
||||
/// glGetShaderInfoLog
|
||||
pub(crate) fn info_log(&self) -> DOMString {
|
||||
self.info_log.borrow().clone()
|
||||
}
|
||||
|
||||
/// Get the shader source
|
||||
pub(crate) fn source(&self) -> DOMString {
|
||||
self.source.borrow().clone()
|
||||
}
|
||||
|
||||
/// glShaderSource
|
||||
pub(crate) fn set_source(&self, source: DOMString) {
|
||||
*self.source.borrow_mut() = source;
|
||||
}
|
||||
|
||||
pub(crate) fn successfully_compiled(&self) -> bool {
|
||||
self.compilation_status.get() == ShaderCompilationStatus::Succeeded
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLShader {
|
||||
fn drop(&mut self) {
|
||||
self.mark_for_deletion(Operation::Fallible);
|
||||
}
|
||||
}
|
66
components/script/dom/webgl/webglshaderprecisionformat.rs
Normal file
66
components/script/dom/webgl/webglshaderprecisionformat.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* 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/. */
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGLShaderPrecisionFormatBinding::WebGLShaderPrecisionFormatMethods;
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLShaderPrecisionFormat {
|
||||
reflector_: Reflector,
|
||||
range_min: i32,
|
||||
range_max: i32,
|
||||
precision: i32,
|
||||
}
|
||||
|
||||
impl WebGLShaderPrecisionFormat {
|
||||
fn new_inherited(range_min: i32, range_max: i32, precision: i32) -> WebGLShaderPrecisionFormat {
|
||||
WebGLShaderPrecisionFormat {
|
||||
reflector_: Reflector::new(),
|
||||
range_min,
|
||||
range_max,
|
||||
precision,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
range_min: i32,
|
||||
range_max: i32,
|
||||
precision: i32,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<WebGLShaderPrecisionFormat> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLShaderPrecisionFormat::new_inherited(
|
||||
range_min, range_max, precision,
|
||||
)),
|
||||
window,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLShaderPrecisionFormatMethods<crate::DomTypeHolder> for WebGLShaderPrecisionFormat {
|
||||
// https://www.khronos.org/registry/webgl/specs/1.0/#5.12.1
|
||||
fn RangeMin(&self) -> i32 {
|
||||
self.range_min
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/1.0/#5.12.1
|
||||
fn RangeMax(&self) -> i32 {
|
||||
self.range_max
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/1.0/#5.12.1
|
||||
fn Precision(&self) -> i32 {
|
||||
self.precision
|
||||
}
|
||||
}
|
137
components/script/dom/webgl/webglsync.rs
Normal file
137
components/script/dom/webgl/webglsync.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{WebGLCommand, WebGLSyncId, webgl_channel};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLSync {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
sync_id: WebGLSyncId,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
client_wait_status: Cell<Option<u32>>,
|
||||
sync_status: Cell<Option<u32>>,
|
||||
}
|
||||
|
||||
impl WebGLSync {
|
||||
fn new_inherited(context: &WebGLRenderingContext, sync_id: WebGLSyncId) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
sync_id,
|
||||
marked_for_deletion: Cell::new(false),
|
||||
client_wait_status: Cell::new(None),
|
||||
sync_status: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::FenceSync(sender));
|
||||
let sync_id = receiver.recv().unwrap();
|
||||
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLSync::new_inherited(context, sync_id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLSync {
|
||||
pub(crate) fn client_wait_sync(
|
||||
&self,
|
||||
context: &WebGLRenderingContext,
|
||||
flags: u32,
|
||||
timeout: u64,
|
||||
) -> Option<u32> {
|
||||
match self.client_wait_status.get() {
|
||||
Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => {
|
||||
let this = Trusted::new(self);
|
||||
let context = Trusted::new(context);
|
||||
let task = task!(request_client_wait_status: move || {
|
||||
let this = this.root();
|
||||
let context = context.root();
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::ClientWaitSync(
|
||||
this.sync_id,
|
||||
flags,
|
||||
timeout,
|
||||
sender,
|
||||
));
|
||||
this.client_wait_status.set(Some(receiver.recv().unwrap()));
|
||||
});
|
||||
self.global()
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
self.client_wait_status.get()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if self.is_valid() {
|
||||
self.marked_for_deletion.set(true);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
let cmd = WebGLCommand::DeleteSync(self.sync_id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_sync_status(
|
||||
&self,
|
||||
pname: u32,
|
||||
context: &WebGLRenderingContext,
|
||||
) -> Option<u32> {
|
||||
match self.sync_status.get() {
|
||||
Some(constants::UNSIGNALED) | None => {
|
||||
let this = Trusted::new(self);
|
||||
let context = Trusted::new(context);
|
||||
let task = task!(request_sync_status: move || {
|
||||
let this = this.root();
|
||||
let context = context.root();
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::GetSyncParameter(this.sync_id, pname, sender));
|
||||
this.sync_status.set(Some(receiver.recv().unwrap()));
|
||||
});
|
||||
self.global()
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
self.sync_status.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_valid(&self) -> bool {
|
||||
!self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> WebGLSyncId {
|
||||
self.sync_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLSync {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
660
components/script/dom/webgl/webgltexture.rs
Normal file
660
components/script/dom/webgl/webgltexture.rs
Normal file
|
@ -0,0 +1,660 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp;
|
||||
|
||||
use canvas_traits::webgl::{
|
||||
TexDataType, TexFormat, TexParameter, TexParameterBool, TexParameterInt, WebGLCommand,
|
||||
WebGLError, WebGLResult, WebGLTextureId, WebGLVersion, webgl_channel,
|
||||
};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding::EXTTextureFilterAnisotropicConstants;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
#[cfg(feature = "webxr")]
|
||||
use crate::dom::bindings::root::Dom;
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::webgl::validations::types::TexImageTarget;
|
||||
use crate::dom::webgl::webglframebuffer::WebGLFramebuffer;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
#[cfg(feature = "webxr")]
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
pub(crate) enum TexParameterValue {
|
||||
Float(f32),
|
||||
Int(i32),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
// Textures generated for WebXR are owned by the WebXR device, not by the WebGL thread
|
||||
// so the GL texture should not be deleted when the texture is garbage collected.
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
enum WebGLTextureOwner {
|
||||
WebGL,
|
||||
#[cfg(feature = "webxr")]
|
||||
WebXR(Dom<XRSession>),
|
||||
}
|
||||
|
||||
const MAX_LEVEL_COUNT: usize = 31;
|
||||
const MAX_FACE_COUNT: usize = 6;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLTexture {
|
||||
webgl_object: WebGLObject,
|
||||
#[no_trace]
|
||||
id: WebGLTextureId,
|
||||
/// The target to which this texture was bound the first time
|
||||
target: Cell<Option<u32>>,
|
||||
is_deleted: Cell<bool>,
|
||||
owner: WebGLTextureOwner,
|
||||
/// Stores information about mipmap levels and cubemap faces.
|
||||
#[ignore_malloc_size_of = "Arrays are cumbersome"]
|
||||
image_info_array: DomRefCell<[Option<ImageInfo>; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
|
||||
/// Face count can only be 1 or 6
|
||||
face_count: Cell<u8>,
|
||||
base_mipmap_level: u32,
|
||||
// Store information for min and mag filters
|
||||
min_filter: Cell<u32>,
|
||||
mag_filter: Cell<u32>,
|
||||
/// Framebuffer that this texture is attached to.
|
||||
attached_framebuffer: MutNullableDom<WebGLFramebuffer>,
|
||||
/// Number of immutable levels.
|
||||
immutable_levels: Cell<Option<u32>>,
|
||||
}
|
||||
|
||||
impl WebGLTexture {
|
||||
fn new_inherited(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLTextureId,
|
||||
#[cfg(feature = "webxr")] owner: Option<&XRSession>,
|
||||
) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
id,
|
||||
target: Cell::new(None),
|
||||
is_deleted: Cell::new(false),
|
||||
#[cfg(feature = "webxr")]
|
||||
owner: owner
|
||||
.map(|session| WebGLTextureOwner::WebXR(Dom::from_ref(session)))
|
||||
.unwrap_or(WebGLTextureOwner::WebGL),
|
||||
#[cfg(not(feature = "webxr"))]
|
||||
owner: WebGLTextureOwner::WebGL,
|
||||
immutable_levels: Cell::new(None),
|
||||
face_count: Cell::new(0),
|
||||
base_mipmap_level: 0,
|
||||
min_filter: Cell::new(constants::NEAREST_MIPMAP_LINEAR),
|
||||
mag_filter: Cell::new(constants::LINEAR),
|
||||
image_info_array: DomRefCell::new([None; MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
|
||||
attached_framebuffer: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateTexture(sender));
|
||||
receiver
|
||||
.recv()
|
||||
.unwrap()
|
||||
.map(|id| WebGLTexture::new(context, id, CanGc::note()))
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLTextureId,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLTexture::new_inherited(
|
||||
context,
|
||||
id,
|
||||
#[cfg(feature = "webxr")]
|
||||
None,
|
||||
)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "webxr")]
|
||||
pub(crate) fn new_webxr(
|
||||
context: &WebGLRenderingContext,
|
||||
id: WebGLTextureId,
|
||||
session: &XRSession,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLTexture::new_inherited(context, id, Some(session))),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLTexture {
|
||||
pub(crate) fn id(&self) -> WebGLTextureId {
|
||||
self.id
|
||||
}
|
||||
|
||||
// NB: Only valid texture targets come here
|
||||
pub(crate) fn bind(&self, target: u32) -> WebGLResult<()> {
|
||||
if self.is_invalid() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if let Some(previous_target) = self.target.get() {
|
||||
if target != previous_target {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
} else {
|
||||
// This is the first time binding
|
||||
let face_count = match target {
|
||||
constants::TEXTURE_2D | constants::TEXTURE_2D_ARRAY | constants::TEXTURE_3D => 1,
|
||||
constants::TEXTURE_CUBE_MAP => 6,
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
};
|
||||
self.face_count.set(face_count);
|
||||
self.target.set(Some(target));
|
||||
}
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::BindTexture(target, Some(self.id)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn initialize(
|
||||
&self,
|
||||
target: TexImageTarget,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
internal_format: TexFormat,
|
||||
level: u32,
|
||||
data_type: Option<TexDataType>,
|
||||
) -> WebGLResult<()> {
|
||||
let image_info = ImageInfo {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
internal_format,
|
||||
data_type,
|
||||
};
|
||||
|
||||
let face_index = self.face_index_for_target(&target);
|
||||
self.set_image_infos_at_level_and_face(level, face_index, image_info);
|
||||
|
||||
if let Some(fb) = self.attached_framebuffer.get() {
|
||||
fb.update_status();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn generate_mipmap(&self) -> WebGLResult<()> {
|
||||
let target = match self.target.get() {
|
||||
Some(target) => target,
|
||||
None => {
|
||||
error!("Cannot generate mipmap on texture that has no target!");
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
},
|
||||
};
|
||||
|
||||
let base_image_info = self.base_image_info().ok_or(WebGLError::InvalidOperation)?;
|
||||
|
||||
let is_cubic = target == constants::TEXTURE_CUBE_MAP;
|
||||
if is_cubic && !self.is_cube_complete() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if !base_image_info.is_power_of_two() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
if base_image_info.is_compressed_format() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::GenerateMipmap(target));
|
||||
|
||||
if self.base_mipmap_level + base_image_info.get_max_mimap_levels() == 0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
let last_level = self.base_mipmap_level + base_image_info.get_max_mimap_levels() - 1;
|
||||
self.populate_mip_chain(self.base_mipmap_level, last_level)
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if !self.is_deleted.get() {
|
||||
self.is_deleted.set(true);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
|
||||
/*
|
||||
If a texture object is deleted while its image is attached to one or more attachment
|
||||
points in a currently bound framebuffer, then it is as if FramebufferTexture had been
|
||||
called, with a texture of zero, for each attachment point to which this im-age was
|
||||
attached in that framebuffer. In other words, this texture image is firstdetached from
|
||||
all attachment points in a currently bound framebuffer.
|
||||
- GLES 3.0, 4.4.2.3, "Attaching Texture Images to a Framebuffer"
|
||||
*/
|
||||
if let Some(fb) = context.get_draw_framebuffer_slot().get() {
|
||||
let _ = fb.detach_texture(self);
|
||||
}
|
||||
if let Some(fb) = context.get_read_framebuffer_slot().get() {
|
||||
let _ = fb.detach_texture(self);
|
||||
}
|
||||
|
||||
// We don't delete textures owned by WebXR
|
||||
#[cfg(feature = "webxr")]
|
||||
if let WebGLTextureOwner::WebXR(_) = self.owner {
|
||||
return;
|
||||
}
|
||||
|
||||
let cmd = WebGLCommand::DeleteTexture(self.id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_invalid(&self) -> bool {
|
||||
// https://immersive-web.github.io/layers/#xrwebglsubimagetype
|
||||
#[cfg(feature = "webxr")]
|
||||
if let WebGLTextureOwner::WebXR(ref session) = self.owner {
|
||||
if session.is_outside_raf() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
self.is_deleted.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_immutable(&self) -> bool {
|
||||
self.immutable_levels.get().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn target(&self) -> Option<u32> {
|
||||
self.target.get()
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_get_tex_parameter(&self, param: TexParameter) -> Option<TexParameterValue> {
|
||||
match param {
|
||||
TexParameter::Int(TexParameterInt::TextureImmutableLevels) => Some(
|
||||
TexParameterValue::Int(self.immutable_levels.get().unwrap_or(0) as i32),
|
||||
),
|
||||
TexParameter::Bool(TexParameterBool::TextureImmutableFormat) => {
|
||||
Some(TexParameterValue::Bool(self.is_immutable()))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// We have to follow the conversion rules for GLES 2.0. See:
|
||||
/// <https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html>
|
||||
pub(crate) fn tex_parameter(&self, param: u32, value: TexParameterValue) -> WebGLResult<()> {
|
||||
let target = self.target().unwrap();
|
||||
|
||||
let (int_value, float_value) = match value {
|
||||
TexParameterValue::Int(int_value) => (int_value, int_value as f32),
|
||||
TexParameterValue::Float(float_value) => (float_value as i32, float_value),
|
||||
TexParameterValue::Bool(_) => unreachable!("no settable tex params should be booleans"),
|
||||
};
|
||||
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
let is_webgl2 = context.webgl_version() == WebGLVersion::WebGL2;
|
||||
|
||||
let update_filter = |filter: &Cell<u32>| {
|
||||
if filter.get() == int_value as u32 {
|
||||
return Ok(());
|
||||
}
|
||||
filter.set(int_value as u32);
|
||||
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
Ok(())
|
||||
};
|
||||
if is_webgl2 {
|
||||
match param {
|
||||
constants::TEXTURE_BASE_LEVEL | constants::TEXTURE_MAX_LEVEL => {
|
||||
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
return Ok(());
|
||||
},
|
||||
constants::TEXTURE_COMPARE_FUNC => match int_value as u32 {
|
||||
constants::LEQUAL |
|
||||
constants::GEQUAL |
|
||||
constants::LESS |
|
||||
constants::GREATER |
|
||||
constants::EQUAL |
|
||||
constants::NOTEQUAL |
|
||||
constants::ALWAYS |
|
||||
constants::NEVER => {
|
||||
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
return Ok(());
|
||||
},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
constants::TEXTURE_COMPARE_MODE => match int_value as u32 {
|
||||
constants::COMPARE_REF_TO_TEXTURE | constants::NONE => {
|
||||
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
return Ok(());
|
||||
},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
constants::TEXTURE_MAX_LOD | constants::TEXTURE_MIN_LOD => {
|
||||
context.send_command(WebGLCommand::TexParameterf(target, param, float_value));
|
||||
return Ok(());
|
||||
},
|
||||
constants::TEXTURE_WRAP_R => match int_value as u32 {
|
||||
constants::CLAMP_TO_EDGE | constants::MIRRORED_REPEAT | constants::REPEAT => {
|
||||
self.upcast::<WebGLObject>()
|
||||
.context()
|
||||
.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
return Ok(());
|
||||
},
|
||||
_ => return Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
match param {
|
||||
constants::TEXTURE_MIN_FILTER => match int_value as u32 {
|
||||
constants::NEAREST |
|
||||
constants::LINEAR |
|
||||
constants::NEAREST_MIPMAP_NEAREST |
|
||||
constants::LINEAR_MIPMAP_NEAREST |
|
||||
constants::NEAREST_MIPMAP_LINEAR |
|
||||
constants::LINEAR_MIPMAP_LINEAR => update_filter(&self.min_filter),
|
||||
_ => Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
constants::TEXTURE_MAG_FILTER => match int_value as u32 {
|
||||
constants::NEAREST | constants::LINEAR => update_filter(&self.mag_filter),
|
||||
_ => Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
constants::TEXTURE_WRAP_S | constants::TEXTURE_WRAP_T => match int_value as u32 {
|
||||
constants::CLAMP_TO_EDGE | constants::MIRRORED_REPEAT | constants::REPEAT => {
|
||||
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(WebGLError::InvalidEnum),
|
||||
},
|
||||
EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT => {
|
||||
// NaN is not less than 1., what a time to be alive.
|
||||
if float_value < 1. || !float_value.is_normal() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
context.send_command(WebGLCommand::TexParameterf(target, param, float_value));
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(WebGLError::InvalidEnum),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn min_filter(&self) -> u32 {
|
||||
self.min_filter.get()
|
||||
}
|
||||
|
||||
pub(crate) fn mag_filter(&self) -> u32 {
|
||||
self.mag_filter.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_using_linear_filtering(&self) -> bool {
|
||||
let filters = [self.min_filter.get(), self.mag_filter.get()];
|
||||
filters.iter().any(|filter| {
|
||||
matches!(
|
||||
*filter,
|
||||
constants::LINEAR |
|
||||
constants::NEAREST_MIPMAP_LINEAR |
|
||||
constants::LINEAR_MIPMAP_NEAREST |
|
||||
constants::LINEAR_MIPMAP_LINEAR
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn populate_mip_chain(&self, first_level: u32, last_level: u32) -> WebGLResult<()> {
|
||||
let base_image_info = self
|
||||
.image_info_at_face(0, first_level)
|
||||
.ok_or(WebGLError::InvalidOperation)?;
|
||||
|
||||
let mut ref_width = base_image_info.width;
|
||||
let mut ref_height = base_image_info.height;
|
||||
|
||||
if ref_width == 0 || ref_height == 0 {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
for level in (first_level + 1)..last_level {
|
||||
if ref_width == 1 && ref_height == 1 {
|
||||
break;
|
||||
}
|
||||
|
||||
ref_width = cmp::max(1, ref_width / 2);
|
||||
ref_height = cmp::max(1, ref_height / 2);
|
||||
|
||||
let image_info = ImageInfo {
|
||||
width: ref_width,
|
||||
height: ref_height,
|
||||
depth: 0,
|
||||
internal_format: base_image_info.internal_format,
|
||||
data_type: base_image_info.data_type,
|
||||
};
|
||||
|
||||
self.set_image_infos_at_level(level, image_info);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_cube_complete(&self) -> bool {
|
||||
debug_assert_eq!(self.face_count.get(), 6);
|
||||
|
||||
let image_info = match self.base_image_info() {
|
||||
Some(info) => info,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let ref_width = image_info.width;
|
||||
let ref_format = image_info.internal_format;
|
||||
|
||||
for face in 0..self.face_count.get() {
|
||||
let current_image_info = match self.image_info_at_face(face, self.base_mipmap_level) {
|
||||
Some(info) => info,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Compares height with width to enforce square dimensions
|
||||
if current_image_info.internal_format != ref_format ||
|
||||
current_image_info.width != ref_width ||
|
||||
current_image_info.height != ref_width
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn face_index_for_target(&self, target: &TexImageTarget) -> u8 {
|
||||
match *target {
|
||||
TexImageTarget::CubeMapPositiveX => 0,
|
||||
TexImageTarget::CubeMapNegativeX => 1,
|
||||
TexImageTarget::CubeMapPositiveY => 2,
|
||||
TexImageTarget::CubeMapNegativeY => 3,
|
||||
TexImageTarget::CubeMapPositiveZ => 4,
|
||||
TexImageTarget::CubeMapNegativeZ => 5,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn image_info_for_target(
|
||||
&self,
|
||||
target: &TexImageTarget,
|
||||
level: u32,
|
||||
) -> Option<ImageInfo> {
|
||||
let face_index = self.face_index_for_target(target);
|
||||
self.image_info_at_face(face_index, level)
|
||||
}
|
||||
|
||||
pub(crate) fn image_info_at_face(&self, face: u8, level: u32) -> Option<ImageInfo> {
|
||||
let pos = (level * self.face_count.get() as u32) + face as u32;
|
||||
self.image_info_array.borrow()[pos as usize]
|
||||
}
|
||||
|
||||
fn set_image_infos_at_level(&self, level: u32, image_info: ImageInfo) {
|
||||
for face in 0..self.face_count.get() {
|
||||
self.set_image_infos_at_level_and_face(level, face, image_info);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_image_infos_at_level_and_face(&self, level: u32, face: u8, image_info: ImageInfo) {
|
||||
debug_assert!(face < self.face_count.get());
|
||||
let pos = (level * self.face_count.get() as u32) + face as u32;
|
||||
self.image_info_array.borrow_mut()[pos as usize] = Some(image_info);
|
||||
}
|
||||
|
||||
fn base_image_info(&self) -> Option<ImageInfo> {
|
||||
assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT);
|
||||
|
||||
self.image_info_at_face(0, self.base_mipmap_level)
|
||||
}
|
||||
|
||||
pub(crate) fn attach_to_framebuffer(&self, fb: &WebGLFramebuffer) {
|
||||
self.attached_framebuffer.set(Some(fb));
|
||||
}
|
||||
|
||||
pub(crate) fn detach_from_framebuffer(&self) {
|
||||
self.attached_framebuffer.set(None);
|
||||
}
|
||||
|
||||
pub(crate) fn storage(
|
||||
&self,
|
||||
target: TexImageTarget,
|
||||
levels: u32,
|
||||
internal_format: TexFormat,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
) -> WebGLResult<()> {
|
||||
// Handled by the caller
|
||||
assert!(!self.is_immutable());
|
||||
assert!(self.target().is_some());
|
||||
|
||||
let target_id = target.as_gl_constant();
|
||||
let command = match target {
|
||||
TexImageTarget::Texture2D | TexImageTarget::CubeMap => {
|
||||
WebGLCommand::TexStorage2D(target_id, levels, internal_format, width, height)
|
||||
},
|
||||
TexImageTarget::Texture3D | TexImageTarget::Texture2DArray => {
|
||||
WebGLCommand::TexStorage3D(target_id, levels, internal_format, width, height, depth)
|
||||
},
|
||||
_ => unreachable!(), // handled by the caller
|
||||
};
|
||||
self.upcast::<WebGLObject>().context().send_command(command);
|
||||
|
||||
let mut width = width;
|
||||
let mut height = height;
|
||||
let mut depth = depth;
|
||||
for level in 0..levels {
|
||||
let image_info = ImageInfo {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
internal_format,
|
||||
data_type: None,
|
||||
};
|
||||
self.set_image_infos_at_level(level, image_info);
|
||||
|
||||
width = cmp::max(1, width / 2);
|
||||
height = cmp::max(1, height / 2);
|
||||
depth = cmp::max(1, depth / 2);
|
||||
}
|
||||
|
||||
self.immutable_levels.set(Some(levels));
|
||||
|
||||
if let Some(fb) = self.attached_framebuffer.get() {
|
||||
fb.update_status();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLTexture {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
pub(crate) struct ImageInfo {
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
#[no_trace]
|
||||
internal_format: TexFormat,
|
||||
#[no_trace]
|
||||
data_type: Option<TexDataType>,
|
||||
}
|
||||
|
||||
impl ImageInfo {
|
||||
pub(crate) fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub(crate) fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub(crate) fn internal_format(&self) -> TexFormat {
|
||||
self.internal_format
|
||||
}
|
||||
|
||||
pub(crate) fn data_type(&self) -> Option<TexDataType> {
|
||||
self.data_type
|
||||
}
|
||||
|
||||
fn is_power_of_two(&self) -> bool {
|
||||
self.width.is_power_of_two() &&
|
||||
self.height.is_power_of_two() &&
|
||||
self.depth.is_power_of_two()
|
||||
}
|
||||
|
||||
fn get_max_mimap_levels(&self) -> u32 {
|
||||
let largest = cmp::max(cmp::max(self.width, self.height), self.depth);
|
||||
if largest == 0 {
|
||||
return 0;
|
||||
}
|
||||
// FloorLog2(largest) + 1
|
||||
(largest as f64).log2() as u32 + 1
|
||||
}
|
||||
|
||||
fn is_compressed_format(&self) -> bool {
|
||||
self.internal_format.is_compressed()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
|
||||
pub(crate) enum TexCompressionValidation {
|
||||
None,
|
||||
S3TC,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
|
||||
pub(crate) struct TexCompression {
|
||||
#[no_trace]
|
||||
pub(crate) format: TexFormat,
|
||||
pub(crate) bytes_per_block: u8,
|
||||
pub(crate) block_width: u8,
|
||||
pub(crate) block_height: u8,
|
||||
pub(crate) validation: TexCompressionValidation,
|
||||
}
|
134
components/script/dom/webgl/webgltransformfeedback.rs
Normal file
134
components/script/dom/webgl/webgltransformfeedback.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use canvas_traits::webgl::{WebGLCommand, webgl_channel};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLTransformFeedback {
|
||||
webgl_object: WebGLObject,
|
||||
id: u32,
|
||||
marked_for_deletion: Cell<bool>,
|
||||
has_been_bound: Cell<bool>,
|
||||
is_active: Cell<bool>,
|
||||
is_paused: Cell<bool>,
|
||||
}
|
||||
|
||||
impl WebGLTransformFeedback {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: u32) -> Self {
|
||||
Self {
|
||||
webgl_object: WebGLObject::new_inherited(context),
|
||||
id,
|
||||
marked_for_deletion: Cell::new(false),
|
||||
has_been_bound: Cell::new(false),
|
||||
is_active: Cell::new(false),
|
||||
is_paused: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
context.send_command(WebGLCommand::CreateTransformFeedback(sender));
|
||||
let id = receiver.recv().unwrap();
|
||||
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLTransformFeedback::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLTransformFeedback {
|
||||
pub(crate) fn bind(&self, context: &WebGLRenderingContext, target: u32) {
|
||||
context.send_command(WebGLCommand::BindTransformFeedback(target, self.id()));
|
||||
self.has_been_bound.set(true);
|
||||
}
|
||||
|
||||
pub(crate) fn begin(&self, context: &WebGLRenderingContext, primitive_mode: u32) {
|
||||
if self.has_been_bound.get() && !self.is_active() {
|
||||
context.send_command(WebGLCommand::BeginTransformFeedback(primitive_mode));
|
||||
self.set_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end(&self, context: &WebGLRenderingContext) {
|
||||
if self.has_been_bound.get() && self.is_active() {
|
||||
if self.is_paused() {
|
||||
context.send_command(WebGLCommand::ResumeTransformFeedback());
|
||||
}
|
||||
context.send_command(WebGLCommand::EndTransformFeedback());
|
||||
self.set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resume(&self, context: &WebGLRenderingContext) {
|
||||
if self.is_active() && self.is_paused() {
|
||||
context.send_command(WebGLCommand::ResumeTransformFeedback());
|
||||
self.set_pause(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn pause(&self, context: &WebGLRenderingContext) {
|
||||
if self.is_active() && !self.is_paused() {
|
||||
context.send_command(WebGLCommand::PauseTransformFeedback());
|
||||
self.set_pause(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn is_valid(&self) -> bool {
|
||||
!self.marked_for_deletion.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_active(&self) -> bool {
|
||||
self.is_active.get()
|
||||
}
|
||||
|
||||
pub(crate) fn is_paused(&self) -> bool {
|
||||
self.is_paused.get()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
if self.is_valid() && self.id() != 0 {
|
||||
self.marked_for_deletion.set(true);
|
||||
let context = self.upcast::<WebGLObject>().context();
|
||||
let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
|
||||
match operation_fallibility {
|
||||
Operation::Fallible => context.send_command_ignored(cmd),
|
||||
Operation::Infallible => context.send_command(cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_active(&self, value: bool) {
|
||||
if self.is_valid() && self.has_been_bound.get() {
|
||||
self.is_active.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_pause(&self, value: bool) {
|
||||
if self.is_valid() && self.is_active() {
|
||||
self.is_active.set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WebGLTransformFeedback {
|
||||
fn drop(&mut self) {
|
||||
self.delete(Operation::Fallible);
|
||||
}
|
||||
}
|
95
components/script/dom/webgl/webgluniformlocation.rs
Normal file
95
components/script/dom/webgl/webgluniformlocation.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* 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/. */
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
|
||||
use canvas_traits::webgl::{WebGLContextId, WebGLProgramId};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLUniformLocation {
|
||||
reflector_: Reflector,
|
||||
id: i32,
|
||||
#[no_trace]
|
||||
context_id: WebGLContextId,
|
||||
#[no_trace]
|
||||
program_id: WebGLProgramId,
|
||||
link_generation: u64,
|
||||
size: Option<i32>,
|
||||
type_: u32,
|
||||
}
|
||||
|
||||
impl WebGLUniformLocation {
|
||||
fn new_inherited(
|
||||
id: i32,
|
||||
context_id: WebGLContextId,
|
||||
program_id: WebGLProgramId,
|
||||
link_generation: u64,
|
||||
size: Option<i32>,
|
||||
type_: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
id,
|
||||
context_id,
|
||||
program_id,
|
||||
link_generation,
|
||||
size,
|
||||
type_,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
id: i32,
|
||||
context_id: WebGLContextId,
|
||||
program_id: WebGLProgramId,
|
||||
link_generation: u64,
|
||||
size: Option<i32>,
|
||||
type_: u32,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(
|
||||
id,
|
||||
context_id,
|
||||
program_id,
|
||||
link_generation,
|
||||
size,
|
||||
type_,
|
||||
)),
|
||||
window,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn program_id(&self) -> WebGLProgramId {
|
||||
self.program_id
|
||||
}
|
||||
|
||||
pub(crate) fn context_id(&self) -> WebGLContextId {
|
||||
self.context_id
|
||||
}
|
||||
|
||||
pub(crate) fn link_generation(&self) -> u64 {
|
||||
self.link_generation
|
||||
}
|
||||
|
||||
pub(crate) fn size(&self) -> Option<i32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub(crate) fn type_(&self) -> u32 {
|
||||
self.type_
|
||||
}
|
||||
}
|
109
components/script/dom/webgl/webglvertexarrayobject.rs
Normal file
109
components/script/dom/webgl/webglvertexarrayobject.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* 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::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::cell::Ref;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::webgl::vertexarrayobject::{VertexArrayObject, VertexAttribData};
|
||||
use crate::dom::webgl::webglbuffer::WebGLBuffer;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLVertexArrayObject {
|
||||
webgl_object_: WebGLObject,
|
||||
array_object: VertexArrayObject,
|
||||
}
|
||||
|
||||
impl WebGLVertexArrayObject {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
|
||||
Self {
|
||||
webgl_object_: WebGLObject::new_inherited(context),
|
||||
array_object: VertexArrayObject::new(context, id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: Option<WebGLVertexArrayId>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLVertexArrayObject::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> Option<WebGLVertexArrayId> {
|
||||
self.array_object.id()
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.array_object.is_deleted()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
self.array_object.delete(operation_fallibility);
|
||||
}
|
||||
|
||||
pub(crate) fn ever_bound(&self) -> bool {
|
||||
self.array_object.ever_bound()
|
||||
}
|
||||
|
||||
pub(crate) fn set_ever_bound(&self) {
|
||||
self.array_object.set_ever_bound();
|
||||
}
|
||||
|
||||
pub(crate) fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
|
||||
self.array_object.element_array_buffer()
|
||||
}
|
||||
|
||||
pub(crate) fn get_vertex_attrib(&self, index: u32) -> Option<Ref<'_, VertexAttribData>> {
|
||||
self.array_object.get_vertex_attrib(index)
|
||||
}
|
||||
|
||||
pub(crate) fn set_vertex_attrib_type(&self, index: u32, type_: u32) {
|
||||
self.array_object.set_vertex_attrib_type(index, type_);
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_pointer(
|
||||
&self,
|
||||
index: u32,
|
||||
size: i32,
|
||||
type_: u32,
|
||||
normalized: bool,
|
||||
stride: i32,
|
||||
offset: i64,
|
||||
) -> WebGLResult<()> {
|
||||
self.array_object
|
||||
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_divisor(&self, index: u32, value: u32) {
|
||||
self.array_object.vertex_attrib_divisor(index, value);
|
||||
}
|
||||
|
||||
pub(crate) fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
|
||||
self.array_object.enabled_vertex_attrib_array(index, value);
|
||||
}
|
||||
|
||||
pub(crate) fn unbind_buffer(&self, buffer: &WebGLBuffer) {
|
||||
self.array_object.unbind_buffer(buffer);
|
||||
}
|
||||
|
||||
pub(crate) fn validate_for_draw(
|
||||
&self,
|
||||
required_len: u32,
|
||||
instance_count: u32,
|
||||
active_attribs: &[ActiveAttribInfo],
|
||||
) -> WebGLResult<()> {
|
||||
self.array_object
|
||||
.validate_for_draw(required_len, instance_count, active_attribs)
|
||||
}
|
||||
}
|
109
components/script/dom/webgl/webglvertexarrayobjectoes.rs
Normal file
109
components/script/dom/webgl/webglvertexarrayobjectoes.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* 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::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::cell::Ref;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::webgl::vertexarrayobject::{VertexArrayObject, VertexAttribData};
|
||||
use crate::dom::webgl::webglbuffer::WebGLBuffer;
|
||||
use crate::dom::webgl::webglobject::WebGLObject;
|
||||
use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct WebGLVertexArrayObjectOES {
|
||||
webgl_object_: WebGLObject,
|
||||
array_object: VertexArrayObject,
|
||||
}
|
||||
|
||||
impl WebGLVertexArrayObjectOES {
|
||||
fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
|
||||
Self {
|
||||
webgl_object_: WebGLObject::new_inherited(context),
|
||||
array_object: VertexArrayObject::new(context, id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
context: &WebGLRenderingContext,
|
||||
id: Option<WebGLVertexArrayId>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLVertexArrayObjectOES::new_inherited(context, id)),
|
||||
&*context.global(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> Option<WebGLVertexArrayId> {
|
||||
self.array_object.id()
|
||||
}
|
||||
|
||||
pub(crate) fn is_deleted(&self) -> bool {
|
||||
self.array_object.is_deleted()
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&self, operation_fallibility: Operation) {
|
||||
self.array_object.delete(operation_fallibility);
|
||||
}
|
||||
|
||||
pub(crate) fn ever_bound(&self) -> bool {
|
||||
self.array_object.ever_bound()
|
||||
}
|
||||
|
||||
pub(crate) fn set_ever_bound(&self) {
|
||||
self.array_object.set_ever_bound();
|
||||
}
|
||||
|
||||
pub(crate) fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
|
||||
self.array_object.element_array_buffer()
|
||||
}
|
||||
|
||||
pub(crate) fn get_vertex_attrib(&self, index: u32) -> Option<Ref<'_, VertexAttribData>> {
|
||||
self.array_object.get_vertex_attrib(index)
|
||||
}
|
||||
|
||||
pub(crate) fn set_vertex_attrib_type(&self, index: u32, type_: u32) {
|
||||
self.array_object.set_vertex_attrib_type(index, type_);
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_pointer(
|
||||
&self,
|
||||
index: u32,
|
||||
size: i32,
|
||||
type_: u32,
|
||||
normalized: bool,
|
||||
stride: i32,
|
||||
offset: i64,
|
||||
) -> WebGLResult<()> {
|
||||
self.array_object
|
||||
.vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
|
||||
}
|
||||
|
||||
pub(crate) fn vertex_attrib_divisor(&self, index: u32, value: u32) {
|
||||
self.array_object.vertex_attrib_divisor(index, value);
|
||||
}
|
||||
|
||||
pub(crate) fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
|
||||
self.array_object.enabled_vertex_attrib_array(index, value);
|
||||
}
|
||||
|
||||
pub(crate) fn unbind_buffer(&self, buffer: &WebGLBuffer) {
|
||||
self.array_object.unbind_buffer(buffer);
|
||||
}
|
||||
|
||||
pub(crate) fn validate_for_draw(
|
||||
&self,
|
||||
required_len: u32,
|
||||
instance_count: u32,
|
||||
active_attribs: &[ActiveAttribInfo],
|
||||
) -> WebGLResult<()> {
|
||||
self.array_object
|
||||
.validate_for_draw(required_len, instance_count, active_attribs)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue