WebGL2: support TexImage3D (#37718)

Add TexImage3D method to WebGL2RenderingContext

Testing: conformance2 should pass. Also it should get
http://webglsamples.org/WebGL2Samples/#texture_2d_array and
http://webglsamples.org/WebGL2Samples/#texture_3d running.
Fixes: #26511

Now Servo can run texture_2d_array and texture_3d samples!

![圖片](https://github.com/user-attachments/assets/41b87563-08b8-4db3-b503-12f3a61dbed7)

![圖片](https://github.com/user-attachments/assets/3c62a4de-35ea-488d-b2e5-00e3aed52090)

And it can now run three.js too!

![圖片](https://github.com/user-attachments/assets/d880aa92-a154-4895-aa06-b7919d1fc869)

---------

Signed-off-by: Wu Yu Wei <yuweiwu@pm.me>
This commit is contained in:
Ngo Iok Ui (Wu Yu Wei) 2025-07-09 23:22:03 +09:00 committed by GitHub
parent 4499fdeb2b
commit 34c31ee418
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 1341 additions and 980 deletions

View file

@ -11,8 +11,8 @@ use std::rc::Rc;
use bitflags::bitflags;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{
GLContextAttributes, InternalFormatParameter, WebGLCommand, WebGLContextId, WebGLResult,
WebGLVersion, webgl_channel,
AlphaTreatment, GLContextAttributes, InternalFormatParameter, TexDataType, TexFormat,
WebGLCommand, WebGLContextId, WebGLResult, WebGLVersion, YAxisTreatment, webgl_channel,
};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
@ -27,6 +27,7 @@ use servo_config::pref;
use url::Host;
use webrender_api::ImageKey;
use super::webgl_validations::types::TexImageTarget;
use crate::canvas_context::CanvasContext;
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
WebGL2RenderingContextConstants as constants, WebGL2RenderingContextMethods,
@ -51,6 +52,7 @@ use crate::dom::webgl_validations::WebGLValidator;
use crate::dom::webgl_validations::tex_image_2d::{
TexImage2DValidator, TexImage2DValidatorResult, TexStorageValidator, TexStorageValidatorResult,
};
use crate::dom::webgl_validations::tex_image_3d::{TexImage3DValidator, TexImage3DValidatorResult};
use crate::dom::webglactiveinfo::WebGLActiveInfo;
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglframebuffer::{WebGLFramebuffer, WebGLFramebufferAttachmentRoot};
@ -899,6 +901,66 @@ impl WebGL2RenderingContext {
texture.storage(target, levels, internal_format, width, height, depth)
);
}
#[allow(clippy::too_many_arguments)]
fn tex_image_3d(
&self,
texture: &WebGLTexture,
target: TexImageTarget,
data_type: TexDataType,
internal_format: TexFormat,
format: TexFormat,
level: u32,
width: u32,
height: u32,
depth: u32,
_border: u32,
unpacking_alignment: u32,
data: TexPixels,
) {
handle_potential_webgl_error!(
self.base,
texture.initialize(
target,
width,
height,
depth,
internal_format,
level,
Some(data_type)
)
);
let internal_format = self
.base
.extension_manager()
.get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
let effective_data_type = self
.base
.extension_manager()
.effective_type(data_type.as_gl_constant());
self.base.send_command(WebGLCommand::TexImage3D {
target: target.as_gl_constant(),
level,
internal_format,
size: data.size(),
depth,
format,
data_type,
effective_data_type,
unpacking_alignment,
alpha_treatment: data.alpha_treatment(),
y_axis_treatment: data.y_axis_treatment(),
pixel_format: data.pixel_format(),
data: data.into_shared_memory().into(),
});
// TODO: Hint/tex_parameter
if let Some(fb) = self.base.bound_draw_framebuffer() {
fb.invalidate_texture(texture);
}
}
}
impl CanvasContext for WebGL2RenderingContext {
@ -2344,6 +2406,8 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
constants::BOOL |
constants::UNSIGNED_INT |
constants::SAMPLER_2D |
constants::SAMPLER_2D_ARRAY |
constants::SAMPLER_3D |
constants::SAMPLER_CUBE => {},
_ => return Err(InvalidOperation),
}
@ -2992,6 +3056,136 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
self.base.Viewport(x, y, width, height)
}
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
///
/// Allocates and initializes the specified mipmap level of a three-dimensional or
/// two-dimensional array texture.
#[allow(unsafe_code)]
fn TexImage3D(
&self,
target: u32,
level: i32,
internal_format: i32,
width: i32,
height: i32,
depth: i32,
border: i32,
format: u32,
type_: u32,
src_data: CustomAutoRooterGuard<Option<ArrayBufferView>>,
) -> Fallible<()> {
// If a WebGLBuffer is bound to the PIXEL_UNPACK_BUFFER target,
// generates an INVALID_OPERATION error.
if self.bound_pixel_unpack_buffer.get().is_some() {
self.base.webgl_error(InvalidOperation);
return Ok(());
}
// If type is specified as FLOAT_32_UNSIGNED_INT_24_8_REV, srcData must be null;
// otherwise, generates an INVALID_OPERATION error.
if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV && src_data.is_some() {
self.base.webgl_error(InvalidOperation);
return Ok(());
}
if border != 0 {
self.base.webgl_error(InvalidValue);
return Ok(());
}
let Ok(TexImage3DValidatorResult {
width,
height,
depth,
level,
border,
texture,
target,
internal_format,
format,
data_type,
}) = TexImage3DValidator::new(
&self.base,
target,
level,
internal_format as u32,
width,
height,
depth,
border,
format,
type_,
&src_data,
)
.validate()
else {
return Ok(());
};
// TODO: If pixel store parameter constraints are not met, generates an INVALID_OPERATION error.
// If srcData is null, a buffer of sufficient size initialized to 0 is passed.
let unpacking_alignment = self.base.texture_unpacking_alignment();
let buff = match *src_data {
Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
None => {
let element_size = data_type.element_size();
let components = format.components();
let components_per_element = format.components();
// FIXME: This is copied from tex_image_2d which is apparently incorrect
// NOTE: width and height are positive or zero due to validate()
let expected_byte_len = if height == 0 {
0
} else {
// We need to be careful here to not count unpack
// alignment at the end of the image, otherwise (for
// example) passing a single byte for uploading a 1x1
// GL_ALPHA/GL_UNSIGNED_BYTE texture would throw an error.
let cpp = element_size * components / components_per_element;
let stride =
(width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
stride * (height - 1) + width * cpp
};
IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_len as usize])
},
};
let (alpha_treatment, y_axis_treatment) =
self.base.get_current_unpack_state(Alpha::NotPremultiplied);
// If UNPACK_FLIP_Y_WEBGL or UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to true, texImage3D and texSubImage3D
// generate an INVALID_OPERATION error if they upload data from a PIXEL_UNPACK_BUFFER or a non-null client
// side ArrayBufferView.
if let (Some(AlphaTreatment::Premultiply), YAxisTreatment::Flipped) =
(alpha_treatment, y_axis_treatment)
{
if src_data.is_some() {
self.base.webgl_error(InvalidOperation);
return Ok(());
}
}
let tex_source = TexPixels::from_array(
buff,
Size2D::new(width, height),
alpha_treatment,
y_axis_treatment,
);
self.tex_image_3d(
&texture,
target,
data_type,
internal_format,
format,
level,
width,
height,
depth,
border,
unpacking_alignment,
tex_source,
);
Ok(())
}
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
fn TexImage2D(
&self,

View file

@ -10,4 +10,5 @@ pub(crate) trait WebGLValidator {
}
pub(crate) mod tex_image_2d;
pub(crate) mod tex_image_3d;
pub(crate) mod types;

View 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::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::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,
})
}
}

View file

@ -143,7 +143,7 @@ pub(crate) unsafe fn uniform_typed<T>(
/// Set of bitflags for texture unpacking (texImage2d, etc...)
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
struct TextureUnpacking(u8);
pub(crate) struct TextureUnpacking(u8);
bitflags! {
impl TextureUnpacking: u8 {
@ -327,6 +327,10 @@ impl WebGLRenderingContext {
self.texture_unpacking_alignment.get()
}
pub(crate) fn bound_draw_framebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
self.bound_draw_framebuffer.get()
}
pub(crate) fn current_vao(&self) -> DomRoot<WebGLVertexArrayObjectOES> {
self.current_vao.or_init(|| {
DomRoot::from_ref(
@ -1680,6 +1684,8 @@ impl WebGLRenderingContext {
constants::BOOL |
constants::INT |
constants::SAMPLER_2D |
WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
WebGL2RenderingContextConstants::SAMPLER_3D |
constants::SAMPLER_CUBE => {},
_ => return Err(InvalidOperation),
}
@ -1687,7 +1693,10 @@ impl WebGLRenderingContext {
let val = self.uniform_vec_section_int(val, src_offset, src_length, 1, location)?;
match location.type_() {
constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
constants::SAMPLER_2D |
constants::SAMPLER_CUBE |
WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
WebGL2RenderingContextConstants::SAMPLER_3D => {
for &v in val
.iter()
.take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
@ -2149,6 +2158,30 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
texture.to_jsval(*cx, retval);
return;
},
WebGL2RenderingContextConstants::TEXTURE_BINDING_2D_ARRAY => unsafe {
let texture = self
.textures
.active_texture_slot(
WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
self.webgl_version(),
)
.unwrap()
.get();
texture.to_jsval(*cx, retval);
return;
},
WebGL2RenderingContextConstants::TEXTURE_BINDING_3D => unsafe {
let texture = self
.textures
.active_texture_slot(
WebGL2RenderingContextConstants::TEXTURE_3D,
self.webgl_version(),
)
.unwrap()
.get();
texture.to_jsval(*cx, retval);
return;
},
constants::TEXTURE_BINDING_CUBE_MAP => unsafe {
let texture = self
.textures
@ -4036,7 +4069,10 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
self.with_location(location, |location| {
match location.type_() {
constants::BOOL | constants::INT => {},
constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
constants::SAMPLER_2D |
WebGL2RenderingContextConstants::SAMPLER_3D |
WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
constants::SAMPLER_CUBE => {
if val < 0 || val as u32 >= self.limits.max_combined_texture_image_units {
return Err(InvalidValue);
}
@ -4237,7 +4273,11 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
constants::BOOL_VEC4 => unsafe {
uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval);
},
constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
constants::INT |
constants::SAMPLER_2D |
constants::SAMPLER_CUBE |
WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
WebGL2RenderingContextConstants::SAMPLER_3D => {
rval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
},
constants::INT_VEC2 => unsafe {
@ -5122,6 +5162,22 @@ impl TexPixels {
pub(crate) fn size(&self) -> Size2D<u32> {
self.size
}
pub(crate) fn pixel_format(&self) -> Option<PixelFormat> {
self.pixel_format
}
pub(crate) fn alpha_treatment(&self) -> Option<AlphaTreatment> {
self.alpha_treatment
}
pub(crate) fn y_axis_treatment(&self) -> YAxisTreatment {
self.y_axis_treatment
}
pub(crate) fn into_shared_memory(self) -> IpcSharedMemory {
self.data
}
}
pub(crate) enum TexSource {

View file

@ -11,7 +11,7 @@ use std::cmp;
use canvas_traits::webgl::{
TexDataType, TexFormat, TexParameter, TexParameterBool, TexParameterInt, WebGLCommand,
WebGLError, WebGLResult, WebGLTextureId, webgl_channel,
WebGLError, WebGLResult, WebGLTextureId, WebGLVersion, webgl_channel,
};
use dom_struct::dom_struct;
@ -158,7 +158,7 @@ impl WebGLTexture {
} else {
// This is the first time binding
let face_count = match target {
constants::TEXTURE_2D => 1,
constants::TEXTURE_2D | constants::TEXTURE_2D_ARRAY | constants::TEXTURE_3D => 1,
constants::TEXTURE_CUBE_MAP => 6,
_ => return Err(WebGLError::InvalidEnum),
};
@ -314,16 +314,60 @@ impl WebGLTexture {
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);
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::TexParameteri(target, param, int_value));
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 |
@ -340,9 +384,7 @@ impl WebGLTexture {
},
constants::TEXTURE_WRAP_S | constants::TEXTURE_WRAP_T => 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));
context.send_command(WebGLCommand::TexParameteri(target, param, int_value));
Ok(())
},
_ => Err(WebGLError::InvalidEnum),
@ -352,9 +394,7 @@ impl WebGLTexture {
if float_value < 1. || !float_value.is_normal() {
return Err(WebGLError::InvalidValue);
}
self.upcast::<WebGLObject>()
.context()
.send_command(WebGLCommand::TexParameterf(target, param, float_value));
context.send_command(WebGLCommand::TexParameterf(target, param, float_value));
Ok(())
},
_ => Err(WebGLError::InvalidEnum),