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
17fn log2(n: u32) -> u32 {
18 31 - n.leading_zeros()
19}
20
21pub(crate) struct CommonTexImage3DValidator<'a> {
22 context: &'a WebGLRenderingContext,
23 target: u32,
24 level: i32,
25 internal_format: u32,
26 width: i32,
27 height: i32,
28 depth: i32,
29 border: i32,
30}
31
32pub(crate) struct CommonTexImage3DValidatorResult {
33 pub(crate) texture: DomRoot<WebGLTexture>,
34 pub(crate) target: TexImageTarget,
35 pub(crate) level: u32,
36 pub(crate) internal_format: TexFormat,
37 pub(crate) width: u32,
38 pub(crate) height: u32,
39 pub(crate) depth: u32,
40 pub(crate) border: u32,
41}
42
43impl WebGLValidator for CommonTexImage3DValidator<'_> {
44 type Error = TexImageValidationError;
45 type ValidatedOutput = CommonTexImage3DValidatorResult;
46 fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
47 let target = match TexImageTarget::from_gl_constant(self.target) {
49 Some(target) if target.dimensions() == 3 => target,
50 _ => {
51 self.context.webgl_error(InvalidEnum);
52 return Err(TexImageValidationError::InvalidTextureTarget(self.target));
53 },
54 };
55
56 let texture = self
57 .context
58 .textures()
59 .active_texture_for_image_target(target);
60 let limits = self.context.limits();
61
62 let max_size = limits.max_3d_tex_size;
63
64 let texture = match texture {
67 Some(texture) => texture,
68 None => {
69 self.context.webgl_error(InvalidOperation);
70 return Err(TexImageValidationError::TextureTargetNotBound(self.target));
71 },
72 };
73
74 let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
77 Some(format)
78 if format.required_webgl_version() <= self.context.webgl_version() &&
79 format.usable_as_internal() =>
80 {
81 format
82 },
83 _ => {
84 self.context.webgl_error(InvalidEnum);
85 return Err(TexImageValidationError::InvalidTextureFormat);
86 },
87 };
88
89 if self.width < 0 || self.height < 0 || self.depth < 0 {
92 self.context.webgl_error(InvalidValue);
93 return Err(TexImageValidationError::NegativeDimension);
94 }
95 let width = self.width as u32;
96 let height = self.height as u32;
97 let depth = self.depth as u32;
98 let level = self.level as u32;
99 if width > max_size || height > max_size || level > max_size {
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 > log2(max_size) {
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 #[allow(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 #[allow(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 data_type = match TexDataType::from_gl_constant(self.data_type) {
237 Some(data_type) if data_type.required_webgl_version() <= context.webgl_version() => {
238 data_type
239 },
240 _ => {
241 context.webgl_error(InvalidEnum);
242 return Err(TexImageValidationError::InvalidDataType);
243 },
244 };
245 let format = match TexFormat::from_gl_constant(self.format) {
246 Some(format) if format.required_webgl_version() <= context.webgl_version() => format,
247 _ => {
248 context.webgl_error(InvalidEnum);
249 return Err(TexImageValidationError::InvalidTextureFormat);
250 },
251 };
252
253 if format != internal_format.to_unsized() {
256 context.webgl_error(InvalidOperation);
257 return Err(TexImageValidationError::TextureFormatMismatch);
258 }
259
260 if !internal_format.compatible_data_types().contains(&data_type) {
261 context.webgl_error(InvalidOperation);
262 return Err(TexImageValidationError::TextureFormatMismatch);
263 }
264
265 if target == TexImageTarget::Texture3D &&
268 (format == TexFormat::DepthComponent || format == TexFormat::DepthStencil)
269 {
270 context.webgl_error(InvalidOperation);
271 return Err(TexImageValidationError::InvalidTypeForFormat);
272 }
273
274 let element_size = data_type.element_size();
277 let received_size = match self.data {
278 Some(buf) => match buf.get_array_type() {
279 Type::Int8 => 1,
280 Type::Uint8 => 1,
281 Type::Int16 => 2,
282 Type::Uint16 => 2,
283 Type::Int32 => 4,
284 Type::Uint32 => 4,
285 Type::Float32 => 4,
286 _ => {
287 context.webgl_error(InvalidOperation);
288 return Err(TexImageValidationError::InvalidTypeForFormat);
289 },
290 },
291 None => element_size,
292 };
293 if received_size != element_size {
294 context.webgl_error(InvalidOperation);
295 return Err(TexImageValidationError::InvalidTypeForFormat);
296 }
297
298 Ok(TexImage3DValidatorResult {
299 width,
300 height,
301 depth,
302 level,
303 border,
304 texture,
305 target,
306 internal_format,
307 format,
308 data_type,
309 })
310 }
311}