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
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;
|
Loading…
Add table
Add a link
Reference in a new issue