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;
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 = self
53 .context
54 .textures()
55 .active_texture_for_image_target(target);
56 let limits = self.context.limits();
57
58 let max_size = limits.max_3d_tex_size;
59
60 let texture = match texture {
63 Some(texture) => texture,
64 None => {
65 self.context.webgl_error(InvalidOperation);
66 return Err(TexImageValidationError::TextureTargetNotBound(self.target));
67 },
68 };
69
70 let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
73 Some(format)
74 if format.required_webgl_version() <= self.context.webgl_version() &&
75 format.usable_as_internal() =>
76 {
77 format
78 },
79 _ => {
80 self.context.webgl_error(InvalidEnum);
81 return Err(TexImageValidationError::InvalidTextureFormat);
82 },
83 };
84
85 if self.width < 0 || self.height < 0 || self.depth < 0 {
88 self.context.webgl_error(InvalidValue);
89 return Err(TexImageValidationError::NegativeDimension);
90 }
91 let width = self.width as u32;
92 let height = self.height as u32;
93 let depth = self.depth as u32;
94 let level = self.level as u32;
95 let max_size_for_level = max_size / 2u32.pow(level);
99 if width > max_size_for_level || height > max_size_for_level || depth > max_size_for_level {
100 self.context.webgl_error(InvalidValue);
101 return Err(TexImageValidationError::TextureTooBig);
102 }
103
104 if self.level < 0 {
107 self.context.webgl_error(InvalidValue);
108 return Err(TexImageValidationError::NegativeLevel);
109 }
110 if level > max_size.ilog2() {
111 self.context.webgl_error(InvalidValue);
112 return Err(TexImageValidationError::LevelTooHigh);
113 }
114
115 if !(self.border == 0 || self.border == 1) {
117 self.context.webgl_error(InvalidValue);
118 return Err(TexImageValidationError::InvalidBorder);
119 }
120
121 Ok(CommonTexImage3DValidatorResult {
122 texture,
123 target,
124 level,
125 internal_format,
126 width,
127 height,
128 depth,
129 border: self.border as u32,
130 })
131 }
132}
133
134impl<'a> CommonTexImage3DValidator<'a> {
135 #[expect(clippy::too_many_arguments)]
136 pub(crate) fn new(
137 context: &'a WebGLRenderingContext,
138 target: u32,
139 level: i32,
140 internal_format: u32,
141 width: i32,
142 height: i32,
143 depth: i32,
144 border: i32,
145 ) -> Self {
146 CommonTexImage3DValidator {
147 context,
148 target,
149 level,
150 internal_format,
151 width,
152 height,
153 depth,
154 border,
155 }
156 }
157}
158
159pub(crate) struct TexImage3DValidator<'a> {
160 common_validator: CommonTexImage3DValidator<'a>,
161 format: u32,
162 data_type: u32,
163 data: &'a Option<ArrayBufferView>,
164}
165
166impl<'a> TexImage3DValidator<'a> {
167 #[expect(clippy::too_many_arguments)]
169 pub(crate) fn new(
170 context: &'a WebGLRenderingContext,
171 target: u32,
172 level: i32,
173 internal_format: u32,
174 width: i32,
175 height: i32,
176 depth: i32,
177 border: i32,
178 format: u32,
179 data_type: u32,
180 data: &'a Option<ArrayBufferView>,
181 ) -> Self {
182 TexImage3DValidator {
183 common_validator: CommonTexImage3DValidator::new(
184 context,
185 target,
186 level,
187 internal_format,
188 width,
189 height,
190 depth,
191 border,
192 ),
193 format,
194 data_type,
195 data,
196 }
197 }
198}
199
200pub(crate) struct TexImage3DValidatorResult {
202 pub(crate) width: u32,
204 pub(crate) height: u32,
205 pub(crate) depth: u32,
206 pub(crate) level: u32,
207 pub(crate) border: u32,
208 pub(crate) texture: DomRoot<WebGLTexture>,
209 pub(crate) target: TexImageTarget,
210 pub(crate) internal_format: TexFormat,
211 pub(crate) format: TexFormat,
212 pub(crate) data_type: TexDataType,
213}
214
215impl WebGLValidator for TexImage3DValidator<'_> {
218 type ValidatedOutput = TexImage3DValidatorResult;
219 type Error = TexImageValidationError;
220
221 fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
222 let context = self.common_validator.context;
223 let CommonTexImage3DValidatorResult {
224 texture,
225 target,
226 level,
227 internal_format,
228 width,
229 height,
230 depth,
231 border,
232 } = self.common_validator.validate()?;
233
234 let version = context.webgl_version();
237 let data_type = match TexDataType::from_webgl_constant(self.data_type, version) {
238 Some(data_type) if data_type.required_webgl_version() <= version => data_type,
239 _ => {
240 context.webgl_error(InvalidEnum);
241 return Err(TexImageValidationError::InvalidDataType);
242 },
243 };
244 let format = match TexFormat::from_gl_constant(self.format) {
245 Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
246 _ => {
247 context.webgl_error(InvalidEnum);
248 return Err(TexImageValidationError::InvalidTextureFormat);
249 },
250 };
251
252 if format != internal_format.to_unsized() {
255 context.webgl_error(InvalidOperation);
256 return Err(TexImageValidationError::TextureFormatMismatch);
257 }
258
259 if !internal_format.compatible_data_types().contains(&data_type) {
260 context.webgl_error(InvalidOperation);
261 return Err(TexImageValidationError::TextureFormatMismatch);
262 }
263
264 if target == TexImageTarget::Texture3D &&
267 (format == TexFormat::DepthComponent || format == TexFormat::DepthStencil)
268 {
269 context.webgl_error(InvalidOperation);
270 return Err(TexImageValidationError::InvalidTypeForFormat);
271 }
272
273 let element_size = data_type.element_size();
276 let received_size = match self.data {
277 Some(buf) => match buf.get_array_type() {
278 Type::Int8 => 1,
279 Type::Uint8 => 1,
280 Type::Int16 => 2,
281 Type::Uint16 => 2,
282 Type::Int32 => 4,
283 Type::Uint32 => 4,
284 Type::Float32 => 4,
285 _ => {
286 context.webgl_error(InvalidOperation);
287 return Err(TexImageValidationError::InvalidTypeForFormat);
288 },
289 },
290 None => element_size,
291 };
292 if received_size != element_size {
293 context.webgl_error(InvalidOperation);
294 return Err(TexImageValidationError::InvalidTypeForFormat);
295 }
296
297 Ok(TexImage3DValidatorResult {
298 width,
299 height,
300 depth,
301 level,
302 border,
303 texture,
304 target,
305 internal_format,
306 format,
307 data_type,
308 })
309 }
310}