script/dom/webgl/validations/
tex_image_3d.rs1use js::jsapi::Type;
6use js::typedarray::ArrayBufferView;
7use servo_canvas_traits::webgl::WebGLError::*;
8use servo_canvas_traits::webgl::{TexDataType, TexFormat};
9
10use super::WebGLValidator;
11use super::tex_image_2d::{TexImageValidationError, bound_texture, validate_internal_format};
12use super::types::TexImageTarget;
13use crate::dom::bindings::root::DomRoot;
14use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
15use crate::dom::webgl::webgltexture::WebGLTexture;
16
17pub(crate) struct CommonTexImage3DValidator<'a> {
18 context: &'a WebGLRenderingContext,
19 target: u32,
20 level: i32,
21 internal_format: u32,
22 width: i32,
23 height: i32,
24 depth: i32,
25 border: i32,
26}
27
28pub(crate) struct CommonTexImage3DValidatorResult {
29 pub(crate) texture: DomRoot<WebGLTexture>,
30 pub(crate) target: TexImageTarget,
31 pub(crate) level: u32,
32 pub(crate) internal_format: TexFormat,
33 pub(crate) width: u32,
34 pub(crate) height: u32,
35 pub(crate) depth: u32,
36 pub(crate) border: u32,
37}
38
39impl WebGLValidator for CommonTexImage3DValidator<'_> {
40 type Error = TexImageValidationError;
41 type ValidatedOutput = CommonTexImage3DValidatorResult;
42 fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
43 let target = match TexImageTarget::from_gl_constant(self.target) {
45 Some(target) if target.dimensions() == 3 => target,
46 _ => {
47 self.context.webgl_error(InvalidEnum);
48 return Err(TexImageValidationError::InvalidTextureTarget(self.target));
49 },
50 };
51
52 let texture = bound_texture(self.context, target)?;
53 let internal_format = validate_internal_format(self.context, self.internal_format)?;
54
55 if self.width < 0 || self.height < 0 || self.depth < 0 {
57 self.context.webgl_error(InvalidValue);
58 return Err(TexImageValidationError::NegativeDimension);
59 }
60 if self.level < 0 {
61 self.context.webgl_error(InvalidValue);
62 return Err(TexImageValidationError::NegativeLevel);
63 }
64 let width = self.width as u32;
65 let height = self.height as u32;
66 let depth = self.depth as u32;
67 let level = self.level as u32;
68
69 let limits = self.context.limits();
72 let (max_size, max_layers) = match target {
73 TexImageTarget::Texture2DArray => {
74 (limits.max_tex_size, Some(limits.max_array_texture_layers))
75 },
76 _ => (limits.max_3d_tex_size, None),
77 };
78
79 if level > max_size.ilog2() {
81 self.context.webgl_error(InvalidValue);
82 return Err(TexImageValidationError::LevelTooHigh);
83 }
84
85 let max_size_for_level = max_size >> level;
87 let max_depth = max_layers.unwrap_or(max_size_for_level);
88 if width > max_size_for_level || height > max_size_for_level || depth > max_depth {
89 self.context.webgl_error(InvalidValue);
90 return Err(TexImageValidationError::TextureTooBig);
91 }
92
93 if !(self.border == 0 || self.border == 1) {
95 self.context.webgl_error(InvalidValue);
96 return Err(TexImageValidationError::InvalidBorder);
97 }
98
99 Ok(CommonTexImage3DValidatorResult {
100 texture,
101 target,
102 level,
103 internal_format,
104 width,
105 height,
106 depth,
107 border: self.border as u32,
108 })
109 }
110}
111
112impl<'a> CommonTexImage3DValidator<'a> {
113 #[expect(clippy::too_many_arguments)]
114 pub(crate) fn new(
115 context: &'a WebGLRenderingContext,
116 target: u32,
117 level: i32,
118 internal_format: u32,
119 width: i32,
120 height: i32,
121 depth: i32,
122 border: i32,
123 ) -> Self {
124 CommonTexImage3DValidator {
125 context,
126 target,
127 level,
128 internal_format,
129 width,
130 height,
131 depth,
132 border,
133 }
134 }
135}
136
137pub(crate) struct TexImage3DValidator<'a> {
138 common_validator: CommonTexImage3DValidator<'a>,
139 format: u32,
140 data_type: u32,
141 data: &'a Option<ArrayBufferView>,
142}
143
144impl<'a> TexImage3DValidator<'a> {
145 #[expect(clippy::too_many_arguments)]
147 pub(crate) fn new(
148 context: &'a WebGLRenderingContext,
149 target: u32,
150 level: i32,
151 internal_format: u32,
152 width: i32,
153 height: i32,
154 depth: i32,
155 border: i32,
156 format: u32,
157 data_type: u32,
158 data: &'a Option<ArrayBufferView>,
159 ) -> Self {
160 TexImage3DValidator {
161 common_validator: CommonTexImage3DValidator::new(
162 context,
163 target,
164 level,
165 internal_format,
166 width,
167 height,
168 depth,
169 border,
170 ),
171 format,
172 data_type,
173 data,
174 }
175 }
176}
177
178pub(crate) struct TexImage3DValidatorResult {
180 pub(crate) width: u32,
182 pub(crate) height: u32,
183 pub(crate) depth: u32,
184 pub(crate) level: u32,
185 pub(crate) border: u32,
186 pub(crate) texture: DomRoot<WebGLTexture>,
187 pub(crate) target: TexImageTarget,
188 pub(crate) internal_format: TexFormat,
189 pub(crate) format: TexFormat,
190 pub(crate) data_type: TexDataType,
191}
192
193impl WebGLValidator for TexImage3DValidator<'_> {
196 type ValidatedOutput = TexImage3DValidatorResult;
197 type Error = TexImageValidationError;
198
199 fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
200 let context = self.common_validator.context;
201 let CommonTexImage3DValidatorResult {
202 texture,
203 target,
204 level,
205 internal_format,
206 width,
207 height,
208 depth,
209 border,
210 } = self.common_validator.validate()?;
211
212 let version = context.webgl_version();
215 let data_type = match TexDataType::from_webgl_constant(self.data_type, version) {
216 Some(data_type) if data_type.required_webgl_version() <= version => data_type,
217 _ => {
218 context.webgl_error(InvalidEnum);
219 return Err(TexImageValidationError::InvalidDataType);
220 },
221 };
222 let format = match TexFormat::from_gl_constant(self.format) {
223 Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
224 _ => {
225 context.webgl_error(InvalidEnum);
226 return Err(TexImageValidationError::InvalidTextureFormat);
227 },
228 };
229
230 if format != internal_format.to_unsized() {
233 context.webgl_error(InvalidOperation);
234 return Err(TexImageValidationError::TextureFormatMismatch);
235 }
236
237 if !internal_format.compatible_data_types().contains(&data_type) {
238 context.webgl_error(InvalidOperation);
239 return Err(TexImageValidationError::TextureFormatMismatch);
240 }
241
242 if target == TexImageTarget::Texture3D &&
245 (format == TexFormat::DepthComponent || format == TexFormat::DepthStencil)
246 {
247 context.webgl_error(InvalidOperation);
248 return Err(TexImageValidationError::InvalidTypeForFormat);
249 }
250
251 let element_size = data_type.element_size();
254 let received_size = match self.data {
255 Some(buf) => match buf.get_array_type() {
256 Type::Int8 => 1,
257 Type::Uint8 => 1,
258 Type::Int16 => 2,
259 Type::Uint16 => 2,
260 Type::Int32 => 4,
261 Type::Uint32 => 4,
262 Type::Float32 => 4,
263 _ => {
264 context.webgl_error(InvalidOperation);
265 return Err(TexImageValidationError::InvalidTypeForFormat);
266 },
267 },
268 None => element_size,
269 };
270 if received_size != element_size {
271 context.webgl_error(InvalidOperation);
272 return Err(TexImageValidationError::InvalidTypeForFormat);
273 }
274
275 Ok(TexImage3DValidatorResult {
276 width,
277 height,
278 depth,
279 level,
280 border,
281 texture,
282 target,
283 internal_format,
284 format,
285 data_type,
286 })
287 }
288}