1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Vladimir Vukicevic <vladimir@pobox.com> (original author)
24 : * Mark Steele <mwsteele@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "WebGLContext.h"
41 :
42 : #include "mozilla/Preferences.h"
43 :
44 : #include "CheckedInt.h"
45 :
46 : #include "jstypedarray.h"
47 :
48 : #if defined(USE_ANGLE)
49 : #include "angle/ShaderLang.h"
50 : #endif
51 :
52 : #include <algorithm>
53 :
54 : using namespace mozilla;
55 :
56 : /*
57 : * Pull data out of the program, post-linking
58 : */
59 : bool
60 0 : WebGLProgram::UpdateInfo()
61 : {
62 0 : mIdentifierMap = nsnull;
63 0 : mIdentifierReverseMap = nsnull;
64 :
65 0 : mAttribMaxNameLength = 0;
66 :
67 0 : for (size_t i = 0; i < mAttachedShaders.Length(); i++)
68 0 : mAttribMaxNameLength = NS_MAX(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
69 :
70 : GLint attribCount;
71 0 : mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
72 :
73 0 : mAttribsInUse.resize(mContext->mGLMaxVertexAttribs);
74 0 : std::fill(mAttribsInUse.begin(), mAttribsInUse.end(), false);
75 :
76 0 : nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
77 :
78 0 : for (int i = 0; i < attribCount; ++i) {
79 : GLint attrnamelen;
80 : GLint attrsize;
81 : GLenum attrtype;
82 0 : mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
83 0 : if (attrnamelen > 0) {
84 0 : GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
85 0 : NS_ABORT_IF_FALSE(loc >= 0, "major oops in managing the attributes of a WebGL program");
86 0 : if (loc < mContext->mGLMaxVertexAttribs) {
87 0 : mAttribsInUse[loc] = true;
88 : } else {
89 0 : mContext->ErrorInvalidOperation("program exceeds MAX_VERTEX_ATTRIBS");
90 0 : return false;
91 : }
92 : }
93 : }
94 :
95 0 : return true;
96 : }
97 :
98 : /*
99 : * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
100 : * that will be legal to be read from bound VBOs.
101 : */
102 :
103 : bool
104 0 : WebGLContext::ValidateBuffers(PRInt32 *maxAllowedCount, const char *info)
105 : {
106 : #ifdef DEBUG
107 0 : GLint currentProgram = 0;
108 0 : MakeContextCurrent();
109 0 : gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram);
110 0 : NS_ASSERTION(GLuint(currentProgram) == mCurrentProgram->GLName(),
111 : "WebGL: current program doesn't agree with GL state");
112 0 : if (GLuint(currentProgram) != mCurrentProgram->GLName())
113 0 : return false;
114 : #endif
115 :
116 0 : *maxAllowedCount = -1;
117 :
118 0 : PRUint32 attribs = mAttribBuffers.Length();
119 0 : for (PRUint32 i = 0; i < attribs; ++i) {
120 0 : const WebGLVertexAttribData& vd = mAttribBuffers[i];
121 :
122 : // If the attrib array isn't enabled, there's nothing to check;
123 : // it's a static value.
124 0 : if (!vd.enabled)
125 0 : continue;
126 :
127 0 : if (vd.buf == nsnull) {
128 0 : ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
129 0 : return false;
130 : }
131 :
132 : // If the attrib is not in use, then we don't have to validate
133 : // it, just need to make sure that the binding is non-null.
134 0 : if (!mCurrentProgram->IsAttribInUse(i))
135 0 : continue;
136 :
137 : // the base offset
138 : CheckedInt32 checked_byteLength
139 0 : = CheckedInt32(vd.buf->ByteLength()) - vd.byteOffset;
140 : CheckedInt32 checked_sizeOfLastElement
141 0 : = CheckedInt32(vd.componentSize()) * vd.size;
142 :
143 0 : if (!checked_byteLength.valid() ||
144 0 : !checked_sizeOfLastElement.valid())
145 : {
146 0 : ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
147 0 : return false;
148 : }
149 :
150 0 : if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
151 0 : *maxAllowedCount = 0;
152 : } else {
153 : CheckedInt32 checked_maxAllowedCount
154 0 : = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
155 :
156 0 : if (!checked_maxAllowedCount.valid()) {
157 0 : ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
158 0 : return false;
159 : }
160 :
161 0 : if (*maxAllowedCount == -1 || *maxAllowedCount > checked_maxAllowedCount.value())
162 0 : *maxAllowedCount = checked_maxAllowedCount.value();
163 : }
164 : }
165 :
166 0 : return true;
167 : }
168 :
169 0 : bool WebGLContext::ValidateCapabilityEnum(WebGLenum cap, const char *info)
170 : {
171 0 : switch (cap) {
172 : case LOCAL_GL_BLEND:
173 : case LOCAL_GL_CULL_FACE:
174 : case LOCAL_GL_DEPTH_TEST:
175 : case LOCAL_GL_DITHER:
176 : case LOCAL_GL_POLYGON_OFFSET_FILL:
177 : case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
178 : case LOCAL_GL_SAMPLE_COVERAGE:
179 : case LOCAL_GL_SCISSOR_TEST:
180 : case LOCAL_GL_STENCIL_TEST:
181 0 : return true;
182 : default:
183 0 : ErrorInvalidEnumInfo(info, cap);
184 0 : return false;
185 : }
186 : }
187 :
188 0 : bool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode, const char *info)
189 : {
190 0 : switch (mode) {
191 : case LOCAL_GL_FUNC_ADD:
192 : case LOCAL_GL_FUNC_SUBTRACT:
193 : case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
194 0 : return true;
195 : default:
196 0 : ErrorInvalidEnumInfo(info, mode);
197 0 : return false;
198 : }
199 : }
200 :
201 0 : bool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor, const char *info)
202 : {
203 0 : switch (factor) {
204 : case LOCAL_GL_ZERO:
205 : case LOCAL_GL_ONE:
206 : case LOCAL_GL_SRC_COLOR:
207 : case LOCAL_GL_ONE_MINUS_SRC_COLOR:
208 : case LOCAL_GL_DST_COLOR:
209 : case LOCAL_GL_ONE_MINUS_DST_COLOR:
210 : case LOCAL_GL_SRC_ALPHA:
211 : case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
212 : case LOCAL_GL_DST_ALPHA:
213 : case LOCAL_GL_ONE_MINUS_DST_ALPHA:
214 : case LOCAL_GL_CONSTANT_COLOR:
215 : case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
216 : case LOCAL_GL_CONSTANT_ALPHA:
217 : case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
218 0 : return true;
219 : default:
220 0 : ErrorInvalidEnumInfo(info, factor);
221 0 : return false;
222 : }
223 : }
224 :
225 0 : bool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor, const char *info)
226 : {
227 0 : if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
228 0 : return true;
229 : else
230 0 : return ValidateBlendFuncDstEnum(factor, info);
231 : }
232 :
233 0 : bool WebGLContext::ValidateBlendFuncEnumsCompatibility(WebGLenum sfactor, WebGLenum dfactor, const char *info)
234 : {
235 : bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
236 0 : sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
237 : bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
238 0 : sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
239 : bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
240 0 : dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
241 : bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
242 0 : dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
243 0 : if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
244 : (dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
245 0 : ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
246 0 : return false;
247 : } else {
248 0 : return true;
249 : }
250 : }
251 :
252 0 : bool WebGLContext::ValidateTextureTargetEnum(WebGLenum target, const char *info)
253 : {
254 0 : switch (target) {
255 : case LOCAL_GL_TEXTURE_2D:
256 : case LOCAL_GL_TEXTURE_CUBE_MAP:
257 0 : return true;
258 : default:
259 0 : ErrorInvalidEnumInfo(info, target);
260 0 : return false;
261 : }
262 : }
263 :
264 0 : bool WebGLContext::ValidateComparisonEnum(WebGLenum target, const char *info)
265 : {
266 0 : switch (target) {
267 : case LOCAL_GL_NEVER:
268 : case LOCAL_GL_LESS:
269 : case LOCAL_GL_LEQUAL:
270 : case LOCAL_GL_GREATER:
271 : case LOCAL_GL_GEQUAL:
272 : case LOCAL_GL_EQUAL:
273 : case LOCAL_GL_NOTEQUAL:
274 : case LOCAL_GL_ALWAYS:
275 0 : return true;
276 : default:
277 0 : ErrorInvalidEnumInfo(info, target);
278 0 : return false;
279 : }
280 : }
281 :
282 0 : bool WebGLContext::ValidateStencilOpEnum(WebGLenum action, const char *info)
283 : {
284 0 : switch (action) {
285 : case LOCAL_GL_KEEP:
286 : case LOCAL_GL_ZERO:
287 : case LOCAL_GL_REPLACE:
288 : case LOCAL_GL_INCR:
289 : case LOCAL_GL_INCR_WRAP:
290 : case LOCAL_GL_DECR:
291 : case LOCAL_GL_DECR_WRAP:
292 : case LOCAL_GL_INVERT:
293 0 : return true;
294 : default:
295 0 : ErrorInvalidEnumInfo(info, action);
296 0 : return false;
297 : }
298 : }
299 :
300 0 : bool WebGLContext::ValidateFaceEnum(WebGLenum face, const char *info)
301 : {
302 0 : switch (face) {
303 : case LOCAL_GL_FRONT:
304 : case LOCAL_GL_BACK:
305 : case LOCAL_GL_FRONT_AND_BACK:
306 0 : return true;
307 : default:
308 0 : ErrorInvalidEnumInfo(info, face);
309 0 : return false;
310 : }
311 : }
312 :
313 0 : bool WebGLContext::ValidateBufferUsageEnum(WebGLenum target, const char *info)
314 : {
315 0 : switch (target) {
316 : case LOCAL_GL_STREAM_DRAW:
317 : case LOCAL_GL_STATIC_DRAW:
318 : case LOCAL_GL_DYNAMIC_DRAW:
319 0 : return true;
320 : default:
321 0 : ErrorInvalidEnumInfo(info, target);
322 0 : return false;
323 : }
324 : }
325 :
326 0 : bool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info)
327 : {
328 0 : switch (mode) {
329 : case LOCAL_GL_TRIANGLES:
330 : case LOCAL_GL_TRIANGLE_STRIP:
331 : case LOCAL_GL_TRIANGLE_FAN:
332 : case LOCAL_GL_POINTS:
333 : case LOCAL_GL_LINE_STRIP:
334 : case LOCAL_GL_LINE_LOOP:
335 : case LOCAL_GL_LINES:
336 0 : return true;
337 : default:
338 0 : ErrorInvalidEnumInfo(info, mode);
339 0 : return false;
340 : }
341 : }
342 :
343 0 : bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
344 : {
345 0 : const PRUint32 maxSize = 256;
346 0 : if (name.Length() > maxSize) {
347 : ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
348 0 : info, name.Length(), maxSize);
349 0 : return false;
350 : }
351 :
352 0 : if (!ValidateGLSLString(name, info)) {
353 0 : return false;
354 : }
355 :
356 0 : return true;
357 : }
358 :
359 0 : bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
360 : {
361 0 : for (PRUint32 i = 0; i < string.Length(); ++i) {
362 0 : if (!ValidateGLSLCharacter(string.CharAt(i))) {
363 0 : ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
364 0 : return false;
365 : }
366 : }
367 :
368 0 : return true;
369 : }
370 :
371 0 : PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
372 : {
373 0 : if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
374 0 : int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
375 0 : switch (format) {
376 : case LOCAL_GL_ALPHA:
377 : case LOCAL_GL_LUMINANCE:
378 0 : return 1 * multiplier;
379 : case LOCAL_GL_LUMINANCE_ALPHA:
380 0 : return 2 * multiplier;
381 : case LOCAL_GL_RGB:
382 0 : return 3 * multiplier;
383 : case LOCAL_GL_RGBA:
384 0 : return 4 * multiplier;
385 : default:
386 : break;
387 0 : }
388 0 : } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
389 : type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
390 : type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
391 : {
392 0 : return 2;
393 : }
394 :
395 0 : NS_ABORT();
396 0 : return 0;
397 : }
398 :
399 0 : bool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
400 : PRUint32 *texelSize, const char *info)
401 : {
402 0 : if (type == LOCAL_GL_UNSIGNED_BYTE ||
403 0 : (IsExtensionEnabled(WebGL_OES_texture_float) && type == LOCAL_GL_FLOAT))
404 : {
405 0 : if (jsArrayType != -1) {
406 0 : if ((type == LOCAL_GL_UNSIGNED_BYTE && jsArrayType != js::TypedArray::TYPE_UINT8) ||
407 : (type == LOCAL_GL_FLOAT && jsArrayType != js::TypedArray::TYPE_FLOAT32))
408 : {
409 0 : ErrorInvalidOperation("%s: invalid typed array type for given format", info);
410 0 : return false;
411 : }
412 : }
413 :
414 0 : int texMultiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
415 0 : switch (format) {
416 : case LOCAL_GL_ALPHA:
417 : case LOCAL_GL_LUMINANCE:
418 0 : *texelSize = 1 * texMultiplier;
419 0 : return true;
420 : case LOCAL_GL_LUMINANCE_ALPHA:
421 0 : *texelSize = 2 * texMultiplier;
422 0 : return true;
423 : case LOCAL_GL_RGB:
424 0 : *texelSize = 3 * texMultiplier;
425 0 : return true;
426 : case LOCAL_GL_RGBA:
427 0 : *texelSize = 4 * texMultiplier;
428 0 : return true;
429 : default:
430 : break;
431 : }
432 :
433 0 : ErrorInvalidEnum("%s: invalid format 0x%x", info, format);
434 0 : return false;
435 : }
436 :
437 0 : switch (type) {
438 : case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
439 : case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
440 0 : if (jsArrayType != -1 && jsArrayType != js::TypedArray::TYPE_UINT16) {
441 0 : ErrorInvalidOperation("%s: invalid typed array type for given format", info);
442 0 : return false;
443 : }
444 :
445 0 : if (format == LOCAL_GL_RGBA) {
446 0 : *texelSize = 2;
447 0 : return true;
448 : }
449 0 : ErrorInvalidOperation("%s: mutually incompatible format and type", info);
450 0 : return false;
451 :
452 : case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
453 0 : if (jsArrayType != -1 && jsArrayType != js::TypedArray::TYPE_UINT16) {
454 0 : ErrorInvalidOperation("%s: invalid typed array type for given format", info);
455 0 : return false;
456 : }
457 :
458 0 : if (format == LOCAL_GL_RGB) {
459 0 : *texelSize = 2;
460 0 : return true;
461 : }
462 0 : ErrorInvalidOperation("%s: mutually incompatible format and type", info);
463 0 : return false;
464 :
465 : default:
466 : break;
467 : }
468 :
469 0 : ErrorInvalidEnum("%s: invalid type 0x%x", info, type);
470 0 : return false;
471 : }
472 :
473 0 : bool WebGLContext::ValidateAttribIndex(WebGLuint index, const char *info)
474 : {
475 0 : if (index >= mAttribBuffers.Length()) {
476 0 : if (index == WebGLuint(-1)) {
477 : ErrorInvalidValue("%s: index -1 is invalid. That probably comes from a getAttribLocation() call, "
478 : "where this return value -1 means that the passed name didn't correspond to an active attribute in "
479 0 : "the specified program.", info);
480 : } else {
481 0 : ErrorInvalidValue("%s: index %d is out of range", info, index);
482 : }
483 0 : return false;
484 : } else {
485 0 : return true;
486 : }
487 : }
488 :
489 0 : bool WebGLContext::ValidateStencilParamsForDrawCall()
490 : {
491 0 : const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
492 0 : if (mStencilRefFront != mStencilRefBack) {
493 0 : ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
494 0 : return false;
495 : }
496 0 : if (mStencilValueMaskFront != mStencilValueMaskBack) {
497 0 : ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
498 0 : return false;
499 : }
500 0 : if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
501 0 : ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
502 0 : return false;
503 : }
504 0 : return true;
505 : }
506 :
507 : bool
508 0 : WebGLContext::InitAndValidateGL()
509 : {
510 0 : if (!gl) return false;
511 :
512 0 : GLenum error = gl->fGetError();
513 0 : if (error != LOCAL_GL_NO_ERROR) {
514 0 : LogMessage("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
515 0 : return false;
516 : }
517 :
518 0 : mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
519 0 : mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
520 :
521 0 : mActiveTexture = 0;
522 0 : mWebGLError = LOCAL_GL_NO_ERROR;
523 :
524 0 : mAttribBuffers.Clear();
525 :
526 0 : mBound2DTextures.Clear();
527 0 : mBoundCubeMapTextures.Clear();
528 :
529 0 : mBoundArrayBuffer = nsnull;
530 0 : mBoundElementArrayBuffer = nsnull;
531 0 : mCurrentProgram = nsnull;
532 :
533 0 : mBoundFramebuffer = nsnull;
534 0 : mBoundRenderbuffer = nsnull;
535 :
536 0 : MakeContextCurrent();
537 :
538 : // on desktop OpenGL, we always keep vertex attrib 0 array enabled
539 0 : if (!gl->IsGLES2()) {
540 0 : gl->fEnableVertexAttribArray(0);
541 : }
542 :
543 0 : if (MinCapabilityMode()) {
544 0 : mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
545 : } else {
546 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
547 : }
548 0 : if (mGLMaxVertexAttribs < 8) {
549 0 : LogMessage("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
550 0 : return false;
551 : }
552 :
553 0 : mAttribBuffers.SetLength(mGLMaxVertexAttribs);
554 :
555 : // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
556 : // even though the hardware supports much more. The
557 : // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
558 0 : if (MinCapabilityMode()) {
559 0 : mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
560 : } else {
561 0 : gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
562 : }
563 0 : if (mGLMaxTextureUnits < 8) {
564 0 : LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
565 0 : return false;
566 : }
567 :
568 0 : mBound2DTextures.SetLength(mGLMaxTextureUnits);
569 0 : mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
570 :
571 0 : if (MinCapabilityMode()) {
572 0 : mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
573 0 : mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
574 0 : mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
575 0 : mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
576 : } else {
577 0 : gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
578 0 : gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
579 0 : gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
580 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
581 : }
582 :
583 : #ifdef XP_MACOSX
584 : if (gl->Vendor() == gl::GLContext::VendorIntel) {
585 : // bug 684882, corruption in large cube maps on Intel Mac driver.
586 : // Is reported to only affect Mac OS < 10.7.2 but don't want to rely on that yet.
587 : mGLMaxCubeMapTextureSize = NS_MIN(mGLMaxCubeMapTextureSize, 512);
588 : }
589 : #endif
590 :
591 0 : if (MinCapabilityMode()) {
592 0 : mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
593 0 : mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
594 0 : mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
595 : } else {
596 0 : if (gl->HasES2Compatibility()) {
597 0 : gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
598 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
599 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
600 : } else {
601 0 : gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
602 0 : mGLMaxFragmentUniformVectors /= 4;
603 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
604 0 : mGLMaxVertexUniformVectors /= 4;
605 :
606 : // we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
607 : // however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
608 : // and check OpenGL error for INVALID_ENUM.
609 :
610 : // before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
611 0 : error = gl->GetAndClearError();
612 0 : if (error != LOCAL_GL_NO_ERROR) {
613 0 : LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
614 0 : return false;
615 : }
616 :
617 : // On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
618 : // mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
619 : GLint maxVertexOutputComponents,
620 : minFragmentInputComponents;
621 0 : gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
622 0 : gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
623 :
624 0 : error = gl->GetAndClearError();
625 0 : switch (error) {
626 : case LOCAL_GL_NO_ERROR:
627 0 : mGLMaxVaryingVectors = NS_MIN(maxVertexOutputComponents, minFragmentInputComponents) / 4;
628 0 : break;
629 : case LOCAL_GL_INVALID_ENUM:
630 0 : mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
631 0 : break;
632 : default:
633 0 : LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
634 0 : return false;
635 : }
636 : }
637 : }
638 :
639 : // Always 1 for GLES2
640 0 : mMaxFramebufferColorAttachments = 1;
641 :
642 0 : if (!gl->IsGLES2()) {
643 : // gl_PointSize is always available in ES2 GLSL, but has to be
644 : // specifically enabled on desktop GLSL.
645 0 : gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
646 :
647 : // we don't do the following glEnable(GL_POINT_SPRITE) on ATI cards on Windows, because bug 602183 shows that it causes
648 : // crashes in the ATI/Windows driver; and point sprites on ATI seem like a lost cause anyway, see
649 : // http://www.gamedev.net/community/forums/topic.asp?topic_id=525643
650 : // Also, if the ATI/Windows driver implements a recent GL spec version, this shouldn't be needed anyway.
651 : #ifdef XP_WIN
652 : if (gl->Vendor() != gl::GLContext::VendorATI)
653 : #else
654 : if (true)
655 : #endif
656 : {
657 : // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
658 : // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
659 : // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
660 0 : gl->fEnable(LOCAL_GL_POINT_SPRITE);
661 : }
662 : }
663 :
664 : // Check the shader validator pref
665 0 : NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
666 :
667 : mShaderValidation =
668 0 : Preferences::GetBool("webgl.shader_validator", mShaderValidation);
669 :
670 : #if defined(USE_ANGLE)
671 : // initialize shader translator
672 0 : if (mShaderValidation) {
673 0 : if (!ShInitialize()) {
674 0 : LogMessage("GLSL translator initialization failed!");
675 0 : return false;
676 : }
677 : }
678 : #endif
679 :
680 : // notice that the point of calling GetAndClearError here is not only to check for error,
681 : // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
682 0 : error = gl->GetAndClearError();
683 0 : if (error != LOCAL_GL_NO_ERROR) {
684 0 : LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
685 0 : return false;
686 : }
687 :
688 0 : return true;
689 : }
|