Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "WebGLContext.h"
7 : #include "WebGLContextUtils.h"
8 : #include "WebGLBuffer.h"
9 : #include "WebGLVertexAttribData.h"
10 : #include "WebGLShader.h"
11 : #include "WebGLProgram.h"
12 : #include "WebGLUniformLocation.h"
13 : #include "WebGLFramebuffer.h"
14 : #include "WebGLRenderbuffer.h"
15 : #include "WebGLShaderPrecisionFormat.h"
16 : #include "WebGLTexture.h"
17 : #include "WebGLExtensions.h"
18 : #include "WebGLVertexArray.h"
19 :
20 : #include "nsString.h"
21 : #include "nsDebug.h"
22 : #include "nsReadableUtils.h"
23 :
24 : #include "gfxContext.h"
25 : #include "gfxPlatform.h"
26 : #include "GLContext.h"
27 :
28 : #include "nsContentUtils.h"
29 : #include "nsError.h"
30 : #include "nsLayoutUtils.h"
31 :
32 : #include "CanvasUtils.h"
33 : #include "gfxUtils.h"
34 :
35 : #include "jsfriendapi.h"
36 :
37 : #include "WebGLTexelConversions.h"
38 : #include "WebGLValidateStrings.h"
39 : #include <algorithm>
40 :
41 : // needed to check if current OS is lower than 10.7
42 : #if defined(MOZ_WIDGET_COCOA)
43 : #include "nsCocoaFeatures.h"
44 : #endif
45 :
46 : #include "mozilla/DebugOnly.h"
47 : #include "mozilla/dom/BindingUtils.h"
48 : #include "mozilla/dom/ImageData.h"
49 : #include "mozilla/dom/ToJSValue.h"
50 : #include "mozilla/EndianUtils.h"
51 :
52 : namespace mozilla {
53 :
54 : static bool
55 0 : IsValidTexTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexTarget,
56 : TexTarget* const out)
57 : {
58 : uint8_t targetDims;
59 :
60 0 : switch (rawTexTarget) {
61 : case LOCAL_GL_TEXTURE_2D:
62 : case LOCAL_GL_TEXTURE_CUBE_MAP:
63 0 : targetDims = 2;
64 0 : break;
65 :
66 : case LOCAL_GL_TEXTURE_3D:
67 : case LOCAL_GL_TEXTURE_2D_ARRAY:
68 0 : if (!webgl->IsWebGL2())
69 0 : return false;
70 :
71 0 : targetDims = 3;
72 0 : break;
73 :
74 : default:
75 0 : return false;
76 : }
77 :
78 : // Some funcs (like GenerateMipmap) doesn't know the dimension, so don't check it.
79 0 : if (funcDims && targetDims != funcDims)
80 0 : return false;
81 :
82 0 : *out = rawTexTarget;
83 0 : return true;
84 : }
85 :
86 : static bool
87 0 : IsValidTexImageTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexImageTarget,
88 : TexImageTarget* const out)
89 : {
90 : uint8_t targetDims;
91 :
92 0 : switch (rawTexImageTarget) {
93 : case LOCAL_GL_TEXTURE_2D:
94 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
95 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
96 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
97 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
98 : case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
99 : case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
100 0 : targetDims = 2;
101 0 : break;
102 :
103 : case LOCAL_GL_TEXTURE_3D:
104 : case LOCAL_GL_TEXTURE_2D_ARRAY:
105 0 : if (!webgl->IsWebGL2())
106 0 : return false;
107 :
108 0 : targetDims = 3;
109 0 : break;
110 :
111 : default:
112 0 : return false;
113 : }
114 :
115 0 : if (targetDims != funcDims)
116 0 : return false;
117 :
118 0 : *out = rawTexImageTarget;
119 0 : return true;
120 : }
121 :
122 : bool
123 0 : ValidateTexTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
124 : GLenum rawTexTarget, TexTarget* const out_texTarget,
125 : WebGLTexture** const out_tex)
126 : {
127 0 : if (webgl->IsContextLost())
128 0 : return false;
129 :
130 0 : TexTarget texTarget;
131 0 : if (!IsValidTexTarget(webgl, funcDims, rawTexTarget, &texTarget)) {
132 0 : webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName);
133 0 : return false;
134 : }
135 :
136 0 : WebGLTexture* tex = webgl->ActiveBoundTextureForTarget(texTarget);
137 0 : if (!tex) {
138 0 : webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName);
139 0 : return false;
140 : }
141 :
142 0 : *out_texTarget = texTarget;
143 0 : *out_tex = tex;
144 0 : return true;
145 : }
146 :
147 : bool
148 0 : ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
149 : GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget,
150 : WebGLTexture** const out_tex)
151 : {
152 0 : if (webgl->IsContextLost())
153 0 : return false;
154 :
155 0 : TexImageTarget texImageTarget;
156 0 : if (!IsValidTexImageTarget(webgl, funcDims, rawTexImageTarget, &texImageTarget)) {
157 0 : webgl->ErrorInvalidEnum("%s: Invalid texImageTarget.", funcName);
158 0 : return false;
159 : }
160 :
161 0 : WebGLTexture* tex = webgl->ActiveBoundTextureForTexImageTarget(texImageTarget);
162 0 : if (!tex) {
163 0 : webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName);
164 0 : return false;
165 : }
166 :
167 0 : *out_texImageTarget = texImageTarget;
168 0 : *out_tex = tex;
169 0 : return true;
170 : }
171 :
172 : /*virtual*/ bool
173 0 : WebGLContext::IsTexParamValid(GLenum pname) const
174 : {
175 0 : switch (pname) {
176 : case LOCAL_GL_TEXTURE_MIN_FILTER:
177 : case LOCAL_GL_TEXTURE_MAG_FILTER:
178 : case LOCAL_GL_TEXTURE_WRAP_S:
179 : case LOCAL_GL_TEXTURE_WRAP_T:
180 0 : return true;
181 :
182 : case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
183 0 : return IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic);
184 :
185 : default:
186 0 : return false;
187 : }
188 : }
189 :
190 : void
191 0 : WebGLContext::InvalidateResolveCacheForTextureWithTexUnit(const GLuint texUnit)
192 : {
193 0 : if (mBound2DTextures[texUnit])
194 0 : mBound2DTextures[texUnit]->InvalidateResolveCache();
195 0 : if (mBoundCubeMapTextures[texUnit])
196 0 : mBoundCubeMapTextures[texUnit]->InvalidateResolveCache();
197 0 : if (mBound3DTextures[texUnit])
198 0 : mBound3DTextures[texUnit]->InvalidateResolveCache();
199 0 : if (mBound2DArrayTextures[texUnit])
200 0 : mBound2DArrayTextures[texUnit]->InvalidateResolveCache();
201 0 : }
202 :
203 : //////////////////////////////////////////////////////////////////////////////////////////
204 : // GL calls
205 :
206 : void
207 0 : WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
208 : {
209 0 : if (IsContextLost())
210 0 : return;
211 :
212 0 : if (newTex && !ValidateObject("bindTexture", *newTex))
213 0 : return;
214 :
215 : // Need to check rawTarget first before comparing against newTex->Target() as
216 : // newTex->Target() returns a TexTarget, which will assert on invalid value.
217 0 : WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
218 0 : switch (rawTarget) {
219 : case LOCAL_GL_TEXTURE_2D:
220 0 : currentTexPtr = &mBound2DTextures[mActiveTexture];
221 0 : break;
222 :
223 : case LOCAL_GL_TEXTURE_CUBE_MAP:
224 0 : currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
225 0 : break;
226 :
227 : case LOCAL_GL_TEXTURE_3D:
228 0 : if (IsWebGL2())
229 0 : currentTexPtr = &mBound3DTextures[mActiveTexture];
230 0 : break;
231 :
232 : case LOCAL_GL_TEXTURE_2D_ARRAY:
233 0 : if (IsWebGL2())
234 0 : currentTexPtr = &mBound2DArrayTextures[mActiveTexture];
235 0 : break;
236 : }
237 :
238 0 : if (!currentTexPtr) {
239 0 : ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
240 0 : return;
241 : }
242 :
243 0 : const TexTarget texTarget(rawTarget);
244 :
245 0 : MakeContextCurrent();
246 :
247 0 : if (newTex) {
248 0 : if (!newTex->BindTexture(texTarget))
249 0 : return;
250 : } else {
251 0 : gl->fBindTexture(texTarget.get(), 0);
252 : }
253 :
254 0 : *currentTexPtr = newTex;
255 : }
256 :
257 : void
258 0 : WebGLContext::GenerateMipmap(GLenum rawTexTarget)
259 : {
260 0 : const char funcName[] = "generateMipmap";
261 0 : const uint8_t funcDims = 0;
262 :
263 0 : TexTarget texTarget;
264 : WebGLTexture* tex;
265 0 : if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
266 0 : return;
267 :
268 0 : tex->GenerateMipmap(texTarget);
269 : }
270 :
271 : JS::Value
272 0 : WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname)
273 : {
274 0 : const char funcName[] = "getTexParameter";
275 0 : const uint8_t funcDims = 0;
276 :
277 0 : TexTarget texTarget;
278 : WebGLTexture* tex;
279 0 : if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
280 0 : return JS::NullValue();
281 :
282 0 : if (!IsTexParamValid(pname)) {
283 0 : ErrorInvalidEnumInfo("getTexParameter: pname", pname);
284 0 : return JS::NullValue();
285 : }
286 :
287 0 : return tex->GetTexParameter(texTarget, pname);
288 : }
289 :
290 : bool
291 0 : WebGLContext::IsTexture(WebGLTexture* tex)
292 : {
293 0 : if (!ValidateIsObject("isTexture", tex))
294 0 : return false;
295 :
296 0 : return tex->IsTexture();
297 : }
298 :
299 : void
300 0 : WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname,
301 : const FloatOrInt& param)
302 : {
303 0 : const char funcName[] = "texParameter";
304 0 : const uint8_t funcDims = 0;
305 :
306 0 : TexTarget texTarget;
307 : WebGLTexture* tex;
308 0 : if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
309 0 : return;
310 :
311 0 : tex->TexParameter(texTarget, pname, param);
312 : }
313 :
314 : //////////////////////////////////////////////////////////////////////////////////////////
315 : // Uploads
316 :
317 : void
318 0 : WebGLContext::CompressedTexImage(const char* funcName, uint8_t funcDims, GLenum rawTarget,
319 : GLint level, GLenum internalFormat, GLsizei width,
320 : GLsizei height, GLsizei depth, GLint border,
321 : const TexImageSource& src)
322 : {
323 0 : TexImageTarget target;
324 : WebGLTexture* tex;
325 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
326 0 : return;
327 :
328 0 : tex->CompressedTexImage(funcName, target, level, internalFormat, width, height, depth,
329 0 : border, src);
330 : }
331 :
332 : void
333 0 : WebGLContext::CompressedTexSubImage(const char* funcName, uint8_t funcDims,
334 : GLenum rawTarget, GLint level, GLint xOffset,
335 : GLint yOffset, GLint zOffset, GLsizei width,
336 : GLsizei height, GLsizei depth, GLenum unpackFormat,
337 : const TexImageSource& src)
338 : {
339 0 : TexImageTarget target;
340 : WebGLTexture* tex;
341 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
342 0 : return;
343 :
344 0 : tex->CompressedTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width,
345 0 : height, depth, unpackFormat, src);
346 : }
347 :
348 : ////
349 :
350 : void
351 0 : WebGLContext::CopyTexImage2D(GLenum rawTarget, GLint level, GLenum internalFormat,
352 : GLint x, GLint y, GLsizei width, GLsizei height,
353 : GLint border)
354 : {
355 0 : const char funcName[] = "copyTexImage2D";
356 0 : const uint8_t funcDims = 2;
357 :
358 0 : TexImageTarget target;
359 : WebGLTexture* tex;
360 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
361 0 : return;
362 :
363 0 : tex->CopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
364 : }
365 :
366 : void
367 0 : WebGLContext::CopyTexSubImage(const char* funcName, uint8_t funcDims, GLenum rawTarget,
368 : GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
369 : GLint x, GLint y, GLsizei width, GLsizei height)
370 : {
371 0 : TexImageTarget target;
372 : WebGLTexture* tex;
373 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
374 0 : return;
375 :
376 0 : tex->CopyTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, x, y, width,
377 0 : height);
378 : }
379 :
380 : ////
381 :
382 : void
383 0 : WebGLContext::TexImage(const char* funcName, uint8_t funcDims, GLenum rawTarget,
384 : GLint level, GLenum internalFormat, GLsizei width, GLsizei height,
385 : GLsizei depth, GLint border, GLenum unpackFormat,
386 : GLenum unpackType, const TexImageSource& src)
387 : {
388 0 : TexImageTarget target;
389 : WebGLTexture* tex;
390 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
391 0 : return;
392 :
393 0 : const webgl::PackingInfo pi = {unpackFormat, unpackType};
394 0 : tex->TexImage(funcName, target, level, internalFormat, width, height, depth, border,
395 0 : pi, src);
396 : }
397 :
398 : void
399 0 : WebGLContext::TexSubImage(const char* funcName, uint8_t funcDims, GLenum rawTarget,
400 : GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
401 : GLsizei width, GLsizei height, GLsizei depth,
402 : GLenum unpackFormat, GLenum unpackType,
403 : const TexImageSource& src)
404 : {
405 0 : TexImageTarget target;
406 : WebGLTexture* tex;
407 0 : if (!ValidateTexImageTarget(this, funcName, funcDims, rawTarget, &target, &tex))
408 0 : return;
409 :
410 0 : const webgl::PackingInfo pi = {unpackFormat, unpackType};
411 0 : tex->TexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width, height,
412 0 : depth, pi, src);
413 : }
414 :
415 : } // namespace mozilla
|