/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGLContext.h" #include #include "angle/ShaderLang.h" #include "CanvasUtils.h" #include "gfxPrefs.h" #include "GLContext.h" #include "jsfriendapi.h" #include "mozilla/CheckedInt.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIObserverService.h" #include "nsPrintfCString.h" #include "WebGLActiveInfo.h" #include "WebGLBuffer.h" #include "WebGLContextUtils.h" #include "WebGLFramebuffer.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" #include "WebGLSampler.h" #include "WebGLShader.h" #include "WebGLTexture.h" #include "WebGLUniformLocation.h" #include "WebGLValidateStrings.h" #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" namespace mozilla { bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info) { switch (mode) { case LOCAL_GL_FUNC_ADD: case LOCAL_GL_FUNC_SUBTRACT: case LOCAL_GL_FUNC_REVERSE_SUBTRACT: return true; case LOCAL_GL_MIN: case LOCAL_GL_MAX: if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) { return true; } break; default: break; } ErrorInvalidEnumInfo(info, mode); return false; } bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char* info) { switch (factor) { case LOCAL_GL_ZERO: case LOCAL_GL_ONE: case LOCAL_GL_SRC_COLOR: case LOCAL_GL_ONE_MINUS_SRC_COLOR: case LOCAL_GL_DST_COLOR: case LOCAL_GL_ONE_MINUS_DST_COLOR: case LOCAL_GL_SRC_ALPHA: case LOCAL_GL_ONE_MINUS_SRC_ALPHA: case LOCAL_GL_DST_ALPHA: case LOCAL_GL_ONE_MINUS_DST_ALPHA: case LOCAL_GL_CONSTANT_COLOR: case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR: case LOCAL_GL_CONSTANT_ALPHA: case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA: return true; default: ErrorInvalidEnumInfo(info, factor); return false; } } bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char* info) { if (factor == LOCAL_GL_SRC_ALPHA_SATURATE) return true; return ValidateBlendFuncDstEnum(factor, info); } bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char* info) { bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR || sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR; bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA || sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA; bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR || dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR; bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA || dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA; if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) || (dfactorIsConstantColor && sfactorIsConstantAlpha) ) { ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in" " the WebGL 1.0 spec", info); return false; } return true; } bool WebGLContext::ValidateComparisonEnum(GLenum target, const char* info) { switch (target) { case LOCAL_GL_NEVER: case LOCAL_GL_LESS: case LOCAL_GL_LEQUAL: case LOCAL_GL_GREATER: case LOCAL_GL_GEQUAL: case LOCAL_GL_EQUAL: case LOCAL_GL_NOTEQUAL: case LOCAL_GL_ALWAYS: return true; default: ErrorInvalidEnumInfo(info, target); return false; } } bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info) { switch (action) { case LOCAL_GL_KEEP: case LOCAL_GL_ZERO: case LOCAL_GL_REPLACE: case LOCAL_GL_INCR: case LOCAL_GL_INCR_WRAP: case LOCAL_GL_DECR: case LOCAL_GL_DECR_WRAP: case LOCAL_GL_INVERT: return true; default: ErrorInvalidEnumInfo(info, action); return false; } } bool WebGLContext::ValidateFaceEnum(GLenum face, const char* info) { switch (face) { case LOCAL_GL_FRONT: case LOCAL_GL_BACK: case LOCAL_GL_FRONT_AND_BACK: return true; default: ErrorInvalidEnumInfo(info, face); return false; } } bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info) { switch (mode) { case LOCAL_GL_TRIANGLES: case LOCAL_GL_TRIANGLE_STRIP: case LOCAL_GL_TRIANGLE_FAN: case LOCAL_GL_POINTS: case LOCAL_GL_LINE_STRIP: case LOCAL_GL_LINE_LOOP: case LOCAL_GL_LINES: return true; default: ErrorInvalidEnumInfo(info, mode); return false; } } bool WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName) { /* GLES 2.0.25, p38: * If the value of location is -1, the Uniform* commands will silently * ignore the data passed in, and the current uniform values will not be * changed. */ if (!loc) return false; if (!ValidateObjectAllowDeleted(funcName, *loc)) return false; if (!mCurrentProgram) { ErrorInvalidOperation("%s: No program is currently bound.", funcName); return false; } return loc->ValidateForProgram(mCurrentProgram, funcName); } bool WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSize, uint32_t arrayLength) { if (IsContextLost()) return false; if (arrayLength < setterElemSize) { ErrorInvalidValue("%s: Array must have >= %d elements.", name, setterElemSize); return false; } return true; } bool WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterElemSize, GLenum setterType, const char* funcName) { if (IsContextLost()) return false; if (!ValidateUniformLocation(loc, funcName)) return false; if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName)) return false; return true; } bool WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc, uint8_t setterElemSize, GLenum setterType, uint32_t setterArraySize, const char* funcName, uint32_t* const out_numElementsToUpload) { if (IsContextLost()) return false; if (!ValidateUniformLocation(loc, funcName)) return false; if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName)) return false; if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName)) return false; const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount; MOZ_ASSERT(elemCount > loc->mArrayIndex); const uint32_t uniformElemCount = elemCount - loc->mArrayIndex; *out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize); return true; } bool WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc, uint8_t setterCols, uint8_t setterRows, GLenum setterType, uint32_t setterArraySize, bool setterTranspose, const char* funcName, uint32_t* const out_numElementsToUpload) { const uint8_t setterElemSize = setterCols * setterRows; if (IsContextLost()) return false; if (!ValidateUniformLocation(loc, funcName)) return false; if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName)) return false; if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName)) return false; if (!ValidateUniformMatrixTranspose(setterTranspose, funcName)) return false; const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount; MOZ_ASSERT(elemCount > loc->mArrayIndex); const uint32_t uniformElemCount = elemCount - loc->mArrayIndex; *out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize); return true; } bool WebGLContext::ValidateAttribIndex(GLuint index, const char* info) { bool valid = (index < MaxVertexAttribs()); if (!valid) { if (index == GLuint(-1)) { ErrorInvalidValue("%s: -1 is not a valid `index`. This value" " probably comes from a getAttribLocation()" " call, where this return value -1 means" " that the passed name didn't correspond to" " an active attribute in the specified" " program.", info); } else { ErrorInvalidValue("%s: `index` must be less than" " MAX_VERTEX_ATTRIBS.", info); } } return valid; } bool WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type, WebGLboolean normalized, GLsizei stride, WebGLintptr byteOffset, const char* info) { WebGLBuffer* buffer = mBoundArrayBuffer; if (!buffer) { ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info); return false; } uint32_t requiredAlignment = 0; if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info)) return false; // requiredAlignment should always be a power of two MOZ_ASSERT(IsPowerOfTwo(requiredAlignment)); GLsizei requiredAlignmentMask = requiredAlignment - 1; if (size < 1 || size > 4) { ErrorInvalidValue("%s: invalid element size", info); return false; } switch (type) { case LOCAL_GL_INT_2_10_10_10_REV: case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: if (size != 4) { ErrorInvalidOperation("%s: size must be 4 for this type.", info); return false; } break; } // see WebGL spec section 6.6 "Vertex Attribute Data Stride" if (stride < 0 || stride > 255) { ErrorInvalidValue("%s: negative or too large stride", info); return false; } if (byteOffset < 0) { ErrorInvalidValue("%s: negative offset", info); return false; } if (stride & requiredAlignmentMask) { ErrorInvalidOperation("%s: stride doesn't satisfy the alignment " "requirement of given type", info); return false; } if (byteOffset & requiredAlignmentMask) { ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment " "requirement of given type", info); return false; } return true; } bool WebGLContext::ValidateStencilParamsForDrawCall() { const char msg[] = "%s set different front and back stencil %s. Drawing in" " this configuration is not allowed."; if (mStencilRefFront != mStencilRefBack) { ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values"); return false; } if (mStencilValueMaskFront != mStencilValueMaskBack) { ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks"); return false; } if (mStencilWriteMaskFront != mStencilWriteMaskBack) { ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks"); return false; } return true; } static inline int32_t FloorPOT(int32_t x) { MOZ_ASSERT(x > 0); int32_t pot = 1; while (pot < 0x40000000) { if (x < pot*2) break; pot *= 2; } return pot; } bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) { MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized"); if (!gl->MakeCurrent(true)) { MOZ_ASSERT(false); *out_failReason = { "FEATURE_FAILURE_WEBGL_MAKECURRENT", "Failed to MakeCurrent for init." }; return false; } // Unconditionally create a new format usage authority. This is // important when restoring contexts and extensions need to add // formats back into the authority. mFormatUsage = CreateFormatUsage(gl); if (!mFormatUsage) { *out_failReason = { "FEATURE_FAILURE_WEBGL_FORMAT", "Failed to create mFormatUsage." }; return false; } GLenum error = gl->fGetError(); if (error != LOCAL_GL_NO_ERROR) { const nsPrintfCString reason("GL error 0x%x occurred during OpenGL context" " initialization, before WebGL initialization!", error); *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_1", reason }; return false; } mMinCapability = gfxPrefs::WebGLMinCapabilityMode(); mDisableExtensions = gfxPrefs::WebGLDisableExtensions(); mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure(); mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground(); mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible(); if (MinCapabilityMode()) mDisableFragHighP = true; // These are the default values, see 6.2 State tables in the // OpenGL ES 2.0.25 spec. mColorWriteMask[0] = 1; mColorWriteMask[1] = 1; mColorWriteMask[2] = 1; mColorWriteMask[3] = 1; mDepthWriteMask = 1; mColorClearValue[0] = 0.f; mColorClearValue[1] = 0.f; mColorClearValue[2] = 0.f; mColorClearValue[3] = 0.f; mDepthClearValue = 1.f; mStencilClearValue = 0; mStencilRefFront = 0; mStencilRefBack = 0; mLineWidth = 1.0; /* // Technically, we should be setting mStencil[...] values to // `allOnes`, but either ANGLE breaks or the SGX540s on Try break. GLuint stencilBits = 0; gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); GLuint allOnes = ~(UINT32_MAX << stencilBits); mStencilValueMaskFront = allOnes; mStencilValueMaskBack = allOnes; mStencilWriteMaskFront = allOnes; mStencilWriteMaskBack = allOnes; */ gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront); gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack); gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront); gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack); AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront); AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack); AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront); AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack); mDitherEnabled = true; mRasterizerDiscardEnabled = false; mScissorTestEnabled = false; mGenerateMipmapHint = LOCAL_GL_DONT_CARE; // Bindings, etc. mActiveTexture = 0; mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK; mEmitContextLostErrorOnce = true; mWebGLError = LOCAL_GL_NO_ERROR; mUnderlyingGLError = LOCAL_GL_NO_ERROR; mBound2DTextures.Clear(); mBoundCubeMapTextures.Clear(); mBound3DTextures.Clear(); mBound2DArrayTextures.Clear(); mBoundSamplers.Clear(); mBoundArrayBuffer = nullptr; mCurrentProgram = nullptr; mBoundDrawFramebuffer = nullptr; mBoundReadFramebuffer = nullptr; mBoundRenderbuffer = nullptr; MakeContextCurrent(); if (MinCapabilityMode()) mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS; else gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs); if (mGLMaxVertexAttribs < 8) { const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs); *out_failReason = { "FEATURE_FAILURE_WEBGL_V_ATRB", reason }; return false; } // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware, // even though the hardware supports much more. The // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value. if (MinCapabilityMode()) mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; else mGLMaxTextureUnits = gl->GetIntAs(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); if (mGLMaxTextureUnits < 8) { const nsPrintfCString reason("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits); *out_failReason = { "FEATURE_FAILURE_WEBGL_T_UNIT", reason }; return false; } mBound2DTextures.SetLength(mGLMaxTextureUnits); mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits); mBound3DTextures.SetLength(mGLMaxTextureUnits); mBound2DArrayTextures.SetLength(mGLMaxTextureUnits); mBoundSamplers.SetLength(mGLMaxTextureUnits); gl->fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, (GLint*)mImplMaxViewportDims); //////////////// if (MinCapabilityMode()) { mImplMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE; mImplMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE; mImplMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE; mImplMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE; mImplMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS; mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS; mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; } else { gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mImplMaxTextureSize); gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mImplMaxCubeMapTextureSize); gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, (GLint*)&mImplMaxRenderbufferSize); if (!gl->GetPotentialInteger(LOCAL_GL_MAX_3D_TEXTURE_SIZE, (GLint*)&mImplMax3DTextureSize)) mImplMax3DTextureSize = 0; if (!gl->GetPotentialInteger(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, (GLint*)&mImplMaxArrayTextureLayers)) mImplMaxArrayTextureLayers = 0; gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits); gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits); } // If we don't support a target, its max size is 0. We should only floor-to-POT if the // value if it's non-zero. (NB log2(0) is -Inf, so zero isn't an integer power-of-two) const auto fnFloorPOTIfSupported = [](uint32_t& val) { if (val) { val = FloorPOT(val); } }; fnFloorPOTIfSupported(mImplMaxTextureSize); fnFloorPOTIfSupported(mImplMaxCubeMapTextureSize); fnFloorPOTIfSupported(mImplMaxRenderbufferSize); fnFloorPOTIfSupported(mImplMax3DTextureSize); fnFloorPOTIfSupported(mImplMaxArrayTextureLayers); //////////////// mGLMaxColorAttachments = 1; mGLMaxDrawBuffers = 1; gl->GetPotentialInteger(LOCAL_GL_MAX_COLOR_ATTACHMENTS, (GLint*)&mGLMaxColorAttachments); gl->GetPotentialInteger(LOCAL_GL_MAX_DRAW_BUFFERS, (GLint*)&mGLMaxDrawBuffers); if (MinCapabilityMode()) { mGLMaxColorAttachments = std::min(mGLMaxColorAttachments, kMinMaxColorAttachments); mGLMaxDrawBuffers = std::min(mGLMaxDrawBuffers, kMinMaxDrawBuffers); } if (IsWebGL2()) { mImplMaxColorAttachments = mGLMaxColorAttachments; mImplMaxDrawBuffers = std::min(mGLMaxDrawBuffers, mImplMaxColorAttachments); } else { mImplMaxColorAttachments = 1; mImplMaxDrawBuffers = 1; } //////////////// if (MinCapabilityMode()) { mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS; mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS; mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS; } else { if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors); gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors); gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors); } else { gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors); mGLMaxFragmentUniformVectors /= 4; gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors); mGLMaxVertexUniformVectors /= 4; /* We are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS * and GL_MAX_FRAGMENT_INPUT_COMPONENTS, however these constants * only entered the OpenGL standard at OpenGL 3.2. So we will try * reading, and check OpenGL error for INVALID_ENUM. * * On the public_webgl list, "problematic GetParameter pnames" * thread, the following formula was given: * maxVaryingVectors = min(GL_MAX_VERTEX_OUTPUT_COMPONENTS, * GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4 */ GLint maxVertexOutputComponents = 0; GLint maxFragmentInputComponents = 0; const bool ok = (gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents) && gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &maxFragmentInputComponents)); if (ok) { mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, maxFragmentInputComponents) / 4; } else { mGLMaxVaryingVectors = 16; // 16 = 64/4, and 64 is the min value for // maxVertexOutputComponents in the OpenGL 3.2 spec. } } } if (gl->IsCompatibilityProfile()) { gl->fEnable(LOCAL_GL_POINT_SPRITE); } if (!gl->IsGLES()) { gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE); } if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) { gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS); } // Check the shader validator pref mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator(); // initialize shader translator if (!ShInitialize()) { *out_failReason = { "FEATURE_FAILURE_WEBGL_GLSL", "GLSL translator initialization failed!" }; return false; } // Mesa can only be detected with the GL_VERSION string, of the form // "2.1 Mesa 7.11.0" const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION)); mIsMesa = strstr(versionStr, "Mesa"); // Notice that the point of calling fGetError here is not only to check for // errors, but also to reset the error flags so that a subsequent WebGL // getError call will give the correct result. error = gl->fGetError(); if (error != LOCAL_GL_NO_ERROR) { const nsPrintfCString reason("GL error 0x%x occurred during WebGL context" " initialization!", error); *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_2", reason }; return false; } if (IsWebGL2() && !InitWebGL2(out_failReason)) { // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL. return false; } mDefaultVertexArray = WebGLVertexArray::Create(this); mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs); mBoundVertexArray = mDefaultVertexArray; // OpenGL core profiles remove the default VAO object from version // 4.0.0. We create a default VAO for all core profiles, // regardless of version. // // GL Spec 4.0.0: // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf) // in Section E.2.2 "Removed Features", pg 397: "[...] The default // vertex array object (the name zero) is also deprecated. [...]" if (gl->IsCoreProfile()) { mDefaultVertexArray->GenVertexArray(); mDefaultVertexArray->BindVertexArray(); } mPixelStore_FlipY = false; mPixelStore_PremultiplyAlpha = false; mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL; // GLES 3.0.4, p259: mPixelStore_UnpackImageHeight = 0; mPixelStore_UnpackSkipImages = 0; mPixelStore_UnpackRowLength = 0; mPixelStore_UnpackSkipRows = 0; mPixelStore_UnpackSkipPixels = 0; mPixelStore_UnpackAlignment = 4; mPixelStore_PackRowLength = 0; mPixelStore_PackSkipRows = 0; mPixelStore_PackSkipPixels = 0; mPixelStore_PackAlignment = 4; mPrimRestartTypeBytes = 0; mGenericVertexAttribTypes.reset(new GLenum[mGLMaxVertexAttribs]); std::fill_n(mGenericVertexAttribTypes.get(), mGLMaxVertexAttribs, LOCAL_GL_FLOAT); static const float kDefaultGenericVertexAttribData[4] = { 0, 0, 0, 1 }; memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData, sizeof(mGenericVertexAttrib0Data)); mFakeVertexAttrib0BufferObject = 0; return true; } bool WebGLContext::ValidateFramebufferTarget(GLenum target, const char* const info) { bool isValid = true; switch (target) { case LOCAL_GL_FRAMEBUFFER: break; case LOCAL_GL_DRAW_FRAMEBUFFER: case LOCAL_GL_READ_FRAMEBUFFER: isValid = IsWebGL2(); break; default: isValid = false; break; } if (MOZ_LIKELY(isValid)) { return true; } ErrorInvalidEnumArg(info, "target", target); return false; } } // namespace mozilla