script/dom/webgl/validations/
tex_image_3d.rs1use canvas_traits::webgl::WebGLError::*;
6use canvas_traits::webgl::{TexDataType, TexFormat};
7use js::jsapi::Type;
8use js::typedarray::ArrayBufferView;
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 if width > max_size || height > max_size || level > max_size {
96 self.context.webgl_error(InvalidValue);
97 return Err(TexImageValidationError::TextureTooBig);
98 }
99
100 if self.level < 0 {
103 self.context.webgl_error(InvalidValue);
104 return Err(TexImageValidationError::NegativeLevel);
105 }
106 if level > max_size.ilog2() {
107 self.context.webgl_error(InvalidValue);
108 return Err(TexImageValidationError::LevelTooHigh);
109 }
110
111 if !(self.border == 0 || self.border == 1) {
113 self.context.webgl_error(InvalidValue);
114 return Err(TexImageValidationError::InvalidBorder);
115 }
116
117 Ok(CommonTexImage3DValidatorResult {
118 texture,
119 target,
120 level,
121 internal_format,
122 width,
123 height,
124 depth,
125 border: self.border as u32,
126 })
127 }
128}
129
130impl<'a> CommonTexImage3DValidator<'a> {
131 #[allow(clippy::too_many_arguments)]
132 pub(crate) fn new(
133 context: &'a WebGLRenderingContext,
134 target: u32,
135 level: i32,
136 internal_format: u32,
137 width: i32,
138 height: i32,
139 depth: i32,
140 border: i32,
141 ) -> Self {
142 CommonTexImage3DValidator {
143 context,
144 target,
145 level,
146 internal_format,
147 width,
148 height,
149 depth,
150 border,
151 }
152 }
153}
154
155pub(crate) struct TexImage3DValidator<'a> {
156 common_validator: CommonTexImage3DValidator<'a>,
157 format: u32,
158 data_type: u32,
159 data: &'a Option<ArrayBufferView>,
160}
161
162impl<'a> TexImage3DValidator<'a> {
163 #[allow(clippy::too_many_arguments)]
165 pub(crate) fn new(
166 context: &'a WebGLRenderingContext,
167 target: u32,
168 level: i32,
169 internal_format: u32,
170 width: i32,
171 height: i32,
172 depth: i32,
173 border: i32,
174 format: u32,
175 data_type: u32,
176 data: &'a Option<ArrayBufferView>,
177 ) -> Self {
178 TexImage3DValidator {
179 common_validator: CommonTexImage3DValidator::new(
180 context,
181 target,
182 level,
183 internal_format,
184 width,
185 height,
186 depth,
187 border,
188 ),
189 format,
190 data_type,
191 data,
192 }
193 }
194}
195
196pub(crate) struct TexImage3DValidatorResult {
198 pub(crate) width: u32,
200 pub(crate) height: u32,
201 pub(crate) depth: u32,
202 pub(crate) level: u32,
203 pub(crate) border: u32,
204 pub(crate) texture: DomRoot<WebGLTexture>,
205 pub(crate) target: TexImageTarget,
206 pub(crate) internal_format: TexFormat,
207 pub(crate) format: TexFormat,
208 pub(crate) data_type: TexDataType,
209}
210
211impl WebGLValidator for TexImage3DValidator<'_> {
214 type ValidatedOutput = TexImage3DValidatorResult;
215 type Error = TexImageValidationError;
216
217 fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
218 let context = self.common_validator.context;
219 let CommonTexImage3DValidatorResult {
220 texture,
221 target,
222 level,
223 internal_format,
224 width,
225 height,
226 depth,
227 border,
228 } = self.common_validator.validate()?;
229
230 let data_type = match TexDataType::from_gl_constant(self.data_type) {
233 Some(data_type) if data_type.required_webgl_version() <= context.webgl_version() => {
234 data_type
235 },
236 _ => {
237 context.webgl_error(InvalidEnum);
238 return Err(TexImageValidationError::InvalidDataType);
239 },
240 };
241 let format = match TexFormat::from_gl_constant(self.format) {
242 Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
243 _ => {
244 context.webgl_error(InvalidEnum);
245 return Err(TexImageValidationError::InvalidTextureFormat);
246 },
247 };
248
249 if format != internal_format.to_unsized() {
252 context.webgl_error(InvalidOperation);
253 return Err(TexImageValidationError::TextureFormatMismatch);
254 }
255
256 if !internal_format.compatible_data_types().contains(&data_type) {
257 context.webgl_error(InvalidOperation);
258 return Err(TexImageValidationError::TextureFormatMismatch);
259 }
260
261 if target == TexImageTarget::Texture3D &&
264 (format == TexFormat::DepthComponent || format == TexFormat::DepthStencil)
265 {
266 context.webgl_error(InvalidOperation);
267 return Err(TexImageValidationError::InvalidTypeForFormat);
268 }
269
270 let element_size = data_type.element_size();
273 let received_size = match self.data {
274 Some(buf) => match buf.get_array_type() {
275 Type::Int8 => 1,
276 Type::Uint8 => 1,
277 Type::Int16 => 2,
278 Type::Uint16 => 2,
279 Type::Int32 => 4,
280 Type::Uint32 => 4,
281 Type::Float32 => 4,
282 _ => {
283 context.webgl_error(InvalidOperation);
284 return Err(TexImageValidationError::InvalidTypeForFormat);
285 },
286 },
287 None => element_size,
288 };
289 if received_size != element_size {
290 context.webgl_error(InvalidOperation);
291 return Err(TexImageValidationError::InvalidTypeForFormat);
292 }
293
294 Ok(TexImage3DValidatorResult {
295 width,
296 height,
297 depth,
298 level,
299 border,
300 texture,
301 target,
302 internal_format,
303 format,
304 data_type,
305 })
306 }
307}