예제 #1
0
webgl::ShaderValidator*
WebGLContext::CreateShaderValidator(GLenum shaderType) const
{
    if (mBypassShaderValidation)
        return nullptr;

    const auto spec = (IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC);
    const auto outputLanguage = ShaderOutput(gl);

    ShBuiltInResources resources;
    memset(&resources, 0, sizeof(resources));
    ShInitBuiltInResources(&resources);

    resources.HashFunction = webgl::IdentifierHashFunc;

    resources.MaxVertexAttribs = mGLMaxVertexAttribs;
    resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
    resources.MaxVaryingVectors = mGLMaxVaryingVectors;
    resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
    resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
    resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
    resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;

    const bool hasMRTs = (IsWebGL2() ||
                          IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers));
    resources.MaxDrawBuffers = (hasMRTs ? mGLMaxDrawBuffers : 1);

    if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
        resources.EXT_frag_depth = 1;

    if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
        resources.OES_standard_derivatives = 1;

    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
        resources.EXT_draw_buffers = 1;

    if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
        resources.EXT_shader_texture_lod = 1;

    // Tell ANGLE to allow highp in frag shaders. (unless disabled)
    // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
    resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;

    if (gl->WorkAroundDriverBugs()) {
#ifdef XP_MACOSX
        if (gl->Vendor() == gl::GLVendor::NVIDIA) {
            // Work around bug 890432
            resources.MaxExpressionComplexity = 1000;
        }
#endif
    }

    const auto compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl);
    return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources,
                                          compileOptions);
}
void
WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
{
    const FuncScope funcScope(*this, "bindTexture");
    if (IsContextLost())
        return;

     if (newTex && !ValidateObject("tex", *newTex))
        return;

    // Need to check rawTarget first before comparing against newTex->Target() as
    // newTex->Target() returns a TexTarget, which will assert on invalid value.
    WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
    switch (rawTarget) {
    case LOCAL_GL_TEXTURE_2D:
        currentTexPtr = &mBound2DTextures[mActiveTexture];
        break;

   case LOCAL_GL_TEXTURE_CUBE_MAP:
        currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
        break;

   case LOCAL_GL_TEXTURE_3D:
        if (IsWebGL2())
            currentTexPtr = &mBound3DTextures[mActiveTexture];
        break;

   case LOCAL_GL_TEXTURE_2D_ARRAY:
        if (IsWebGL2())
            currentTexPtr = &mBound2DArrayTextures[mActiveTexture];
        break;
    }

    if (!currentTexPtr) {
        ErrorInvalidEnumInfo("target", rawTarget);
        return;
    }

    const TexTarget texTarget(rawTarget);
    if (newTex) {
        if (!newTex->BindTexture(texTarget))
            return;
    } else {
        gl->fBindTexture(texTarget.get(), 0);
    }

    *currentTexPtr = newTex;
}
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::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;
    }

    ErrorInvalidEnum("%s: Invalid target: %s (0x%04x).", info, EnumName(target),
                     target);
    return false;
}
예제 #5
0
WebGLRefPtr<WebGLQuery>* WebGLContext::ValidateQuerySlotByTarget(
    GLenum target) {
  if (IsWebGL2()) {
    switch (target) {
      case LOCAL_GL_ANY_SAMPLES_PASSED:
      case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
        return &mQuerySlot_SamplesPassed;

      case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
        return &mQuerySlot_TFPrimsWritten;

      default:
        break;
    }
  }

  if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
    switch (target) {
      case LOCAL_GL_TIME_ELAPSED_EXT:
        return &mQuerySlot_TimeElapsed;

      default:
        break;
    }
  }

  ErrorInvalidEnumInfo("target", target);
  return nullptr;
}
예제 #6
0
bool
WebGLContext::InitWebGL2()
{
    MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");

    // check OpenGL features
    if (!gl->IsSupported(gl::GLFeature::occlusion_query) &&
        !gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
    {
        // On desktop, we fake occlusion_query_boolean with occlusion_query if
        // necessary. (See WebGL2ContextQueries.cpp)
        GenerateWarning("WebGL 2 unavailable. Requires occlusion queries.");
        return false;
    }

    std::vector<gl::GLFeature> missingList;

    for (size_t i = 0; i < ArrayLength(kRequiredFeatures); i++) {
        if (!gl->IsSupported(kRequiredFeatures[i]))
            missingList.push_back(kRequiredFeatures[i]);
    }

    if (missingList.size()) {
        nsAutoCString exts;
        for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) {
            exts.AppendLiteral("\n  ");
            exts.Append(gl::GLContext::GetFeatureName(*itr));
        }
        GenerateWarning("WebGL 2 unavailable. The following required features are"
                        " unavailible: %s", exts.BeginReading());
        return false;
    }

    // ok WebGL 2 is compatible, we can enable natively supported extensions.
    for (size_t i = 0; i < ArrayLength(kNativelySupportedExtensions); i++) {
        EnableExtension(kNativelySupportedExtensions[i]);

        MOZ_ASSERT(IsExtensionEnabled(kNativelySupportedExtensions[i]));
    }

    // we initialise WebGL 2 related stuff.
    gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                     &mGLMaxTransformFeedbackSeparateAttribs);
    gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
                     &mGLMaxUniformBufferBindings);

    mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
    mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);

    mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
    mBoundTransformFeedback = mDefaultTransformFeedback;

    mBypassShaderValidation = true;

    return true;
}
예제 #7
0
void
WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
{
    if (IsContextLost())
        return;

    if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
        return;

    if (!buffer || buffer->IsDeleted())
        return;

    ////

    const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
        if (bindPoint == buffer) {
            bindPoint = nullptr;
        }
    };

    fnClearIfBuffer(mBoundArrayBuffer);
    fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);

    // WebGL binding points
    if (IsWebGL2()) {
        fnClearIfBuffer(mBoundCopyReadBuffer);
        fnClearIfBuffer(mBoundCopyWriteBuffer);
        fnClearIfBuffer(mBoundPixelPackBuffer);
        fnClearIfBuffer(mBoundPixelUnpackBuffer);
        fnClearIfBuffer(mBoundUniformBuffer);
        fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);

        if (!mBoundTransformFeedback->mIsActive) {
            for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
                fnClearIfBuffer(binding.mBufferBinding);
            }
        }

        for (auto& binding : mIndexedUniformBufferBindings) {
            fnClearIfBuffer(binding.mBufferBinding);
        }
    }

    for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
        if (mBoundVertexArray->HasAttrib(i)) {
            fnClearIfBuffer(mBoundVertexArray->mAttribs[i].mBuf);
        }
    }

    ////

    buffer->RequestDelete();
}
예제 #8
0
void WebGLContext::AssertCachedBindings() const {
#ifdef DEBUG
  gl::GLContext::LocalErrorScope errorScope(*gl);

  if (IsWebGL2() ||
      IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
    AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING,
                           mBoundVertexArray->mGLName);
  }

  GLint stencilBits = 0;
  if (GetStencilBits(&stencilBits)) {  // Depends on current draw framebuffer.
    const GLuint stencilRefMask = (1 << stencilBits) - 1;

    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask,
                                 mStencilRefFront);
    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask,
                                 mStencilRefBack);
  }

  // Program
  GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
  AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);

  // Textures
  GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
  AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);

  WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
  bound = curTex ? curTex->mGLName : 0;
  AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound);

  curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP);
  bound = curTex ? curTex->mGLName : 0;
  AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound);

  // Buffers
  bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0;
  AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound);

  MOZ_ASSERT(mBoundVertexArray);
  WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer;
  bound = curBuff ? curBuff->mGLName : 0;
  AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound);

  MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError()));
#endif

  // We do not check the renderbuffer binding, because we never rely on it
  // matching.
}
예제 #9
0
WebGLRefPtr<WebGLBuffer>*
WebGLContext::ValidateBufferSlot(const char* funcName, GLenum target)
{
    WebGLRefPtr<WebGLBuffer>* slot = nullptr;

    switch (target) {
    case LOCAL_GL_ARRAY_BUFFER:
        slot = &mBoundArrayBuffer;
        break;

    case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
        slot = &(mBoundVertexArray->mElementArrayBuffer);
        break;
    }

    if (IsWebGL2()) {
        switch (target) {
        case LOCAL_GL_COPY_READ_BUFFER:
            slot = &mBoundCopyReadBuffer;
            break;

        case LOCAL_GL_COPY_WRITE_BUFFER:
            slot = &mBoundCopyWriteBuffer;
            break;

        case LOCAL_GL_PIXEL_PACK_BUFFER:
            slot = &mBoundPixelPackBuffer;
            break;

        case LOCAL_GL_PIXEL_UNPACK_BUFFER:
            slot = &mBoundPixelUnpackBuffer;
            break;

        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
            slot = &(mBoundTransformFeedback->mGenericBufferBinding);
            break;

        case LOCAL_GL_UNIFORM_BUFFER:
            slot = &mBoundUniformBuffer;
            break;
        }
    }

    if (!slot) {
        ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
        return nullptr;
    }

    return slot;
}
예제 #10
0
bool
WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
                               GLsizei vertCount, GLsizei instanceCount)
{
    if (!ValidateDrawModeEnum(mode, funcName))
        return false;

    if (!ValidateNonNegative(funcName, "first", first) ||
        !ValidateNonNegative(funcName, "vertCount", vertCount) ||
        !ValidateNonNegative(funcName, "instanceCount", instanceCount))
    {
        return false;
    }

    if (!ValidateStencilParamsForDrawCall())
        return false;

    if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
        MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
        if (mPrimRestartTypeBytes != 0) {
            mPrimRestartTypeBytes = 0;

            // OSX appears to have severe perf issues with leaving this enabled.
            gl->fDisable(LOCAL_GL_PRIMITIVE_RESTART);
        }
    }

    if (!vertCount || !instanceCount)
        return false; // No error, just early out.

    if (!ValidateBufferFetching(funcName))
        return false;

    const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
    if (!checked_firstPlusCount.isValid()) {
        ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
        return false;
    }

    if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
        ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
                              " size for given first and count.",
                              funcName);
        return false;
    }

    return true;
}
예제 #11
0
void WebGLContext::DeleteBuffer(WebGLBuffer* buffer) {
  const FuncScope funcScope(*this, "deleteBuffer");
  if (!ValidateDeleteObject(buffer)) return;

  ////

  const auto fnClearIfBuffer = [&](GLenum target,
                                   WebGLRefPtr<WebGLBuffer>& bindPoint) {
    if (bindPoint == buffer) {
      WebGLBuffer::SetSlot(target, nullptr, &bindPoint);
    }
  };

  fnClearIfBuffer(0, mBoundArrayBuffer);
  fnClearIfBuffer(0, mBoundVertexArray->mElementArrayBuffer);

  for (auto& cur : mBoundVertexArray->mAttribs) {
    fnClearIfBuffer(0, cur.mBuf);
  }

  // WebGL binding points
  if (IsWebGL2()) {
    fnClearIfBuffer(0, mBoundCopyReadBuffer);
    fnClearIfBuffer(0, mBoundCopyWriteBuffer);
    fnClearIfBuffer(0, mBoundPixelPackBuffer);
    fnClearIfBuffer(0, mBoundPixelUnpackBuffer);
    fnClearIfBuffer(0, mBoundUniformBuffer);
    fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
                    mBoundTransformFeedbackBuffer);

    if (!mBoundTransformFeedback->mIsActive) {
      for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
        fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
                        binding.mBufferBinding);
      }
    }

    for (auto& binding : mIndexedUniformBufferBindings) {
      fnClearIfBuffer(0, binding.mBufferBinding);
    }
  }

  ////

  buffer->RequestDelete();
}
예제 #12
0
void
WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
{
    if (IsContextLost())
        return;

     if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
        return;

    // Need to check rawTarget first before comparing against newTex->Target() as
    // newTex->Target() returns a TexTarget, which will assert on invalid value.
    WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
    switch (rawTarget) {
        case LOCAL_GL_TEXTURE_2D:
            currentTexPtr = &mBound2DTextures[mActiveTexture];
            break;

       case LOCAL_GL_TEXTURE_CUBE_MAP:
            currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
            break;

       case LOCAL_GL_TEXTURE_3D:
            if (!IsWebGL2())
                return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");

            currentTexPtr = &mBound3DTextures[mActiveTexture];
            break;

       default:
            return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
    }
    const TexTarget texTarget(rawTarget);

    MakeContextCurrent();

    if (newTex && !newTex->BindTexture(texTarget))
        return;

    if (!newTex) {
        gl->fBindTexture(texTarget.get(), 0);
    }

    *currentTexPtr = newTex;
}
예제 #13
0
bool
WebGLContext::DrawInstanced_check(const char* info)
{
    MOZ_ASSERT(IsWebGL2() ||
               IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
    if (!mBufferFetchingHasPerVertex) {
        /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
         *  If all of the enabled vertex attribute arrays that are bound to active
         *  generic attributes in the program have a non-zero divisor, the draw
         *  call should return INVALID_OPERATION.
         *
         * NB: This also appears to apply to NV_instanced_arrays, though the
         * INVALID_OPERATION emission is not explicitly stated.
         * ARB_instanced_arrays does not have this restriction.
         */
        ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
        return false;
    }

    return true;
}
예제 #14
0
bool
WebGLContext::ValidateCapabilityEnum(GLenum cap, const char* info)
{
    switch (cap) {
        case LOCAL_GL_BLEND:
        case LOCAL_GL_CULL_FACE:
        case LOCAL_GL_DEPTH_TEST:
        case LOCAL_GL_DITHER:
        case LOCAL_GL_POLYGON_OFFSET_FILL:
        case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
        case LOCAL_GL_SAMPLE_COVERAGE:
        case LOCAL_GL_SCISSOR_TEST:
        case LOCAL_GL_STENCIL_TEST:
            return true;
        case LOCAL_GL_RASTERIZER_DISCARD:
            return IsWebGL2();
        default:
            ErrorInvalidEnumInfo(info, cap);
            return false;
    }
}
bool
WebGLContext::ValidateTextureTargetEnum(GLenum target, const char* info)
{
    switch (target) {
    case LOCAL_GL_TEXTURE_2D:
    case LOCAL_GL_TEXTURE_CUBE_MAP:
        return true;

    case LOCAL_GL_TEXTURE_3D:
        if (IsWebGL2())
            return true;

        break;

    default:
        break;
    }

    ErrorInvalidEnumInfo(info, target);
    return false;
}
예제 #16
0
void
WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
{
    if (IsContextLost())
        return;

    if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
        return;

    if (!buffer || buffer->IsDeleted())
        return;

    // TODO: Extract this into a helper function?
    if (mBoundArrayBuffer == buffer) {
        WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
        mBoundArrayBuffer = nullptr;
    }

    if (mBoundVertexArray->mElementArrayBuffer == buffer) {
        WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
        mBoundVertexArray->mElementArrayBuffer = nullptr;
    }

    // WebGL binding points
    if (IsWebGL2()) {
        if (mBoundCopyReadBuffer == buffer)
            mBoundCopyReadBuffer = nullptr;

        if (mBoundCopyWriteBuffer == buffer)
            mBoundCopyWriteBuffer = nullptr;

        if (mBoundPixelPackBuffer == buffer)
            mBoundPixelPackBuffer = nullptr;

        if (mBoundPixelUnpackBuffer == buffer)
            mBoundPixelUnpackBuffer = nullptr;

        if (mBoundTransformFeedbackBuffer == buffer)
            mBoundTransformFeedbackBuffer = nullptr;

        if (mBoundUniformBuffer == buffer)
            mBoundUniformBuffer = nullptr;

        const size_t xfBufferCount = mBoundTransformFeedbackBuffers.Length();
        for (size_t n = 0; n < xfBufferCount; n++) {
            if (mBoundTransformFeedbackBuffers[n] == buffer) {
                mBoundTransformFeedbackBuffers[n] = nullptr;
            }
        }

        const size_t uniformBufferCount = mBoundUniformBuffers.Length();
        for (size_t n = 0; n < uniformBufferCount; n++) {
            if (mBoundUniformBuffers[n] == buffer) {
                mBoundUniformBuffers[n] = nullptr;
            }
        }
    }

    for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
        if (mBoundVertexArray->HasAttrib(i) &&
            mBoundVertexArray->mAttribs[i].buf == buffer)
        {
            mBoundVertexArray->mAttribs[i].buf = nullptr;
        }
    }

    buffer->RequestDelete();
}
예제 #17
0
void WebGLContext::AssertCachedGlobalState() const {
#ifdef DEBUG
  gl::GLContext::LocalErrorScope errorScope(*gl);

  ////////////////

  // Draw state
  MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
  MOZ_ASSERT_IF(IsWebGL2(), gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) ==
                                mRasterizerDiscardEnabled);
  MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);

  // Cannot trivially check COLOR_CLEAR_VALUE, since in old GL versions glGet
  // may clamp based on whether the current framebuffer is floating-point or
  // not. This also means COLOR_CLEAR_VALUE save+restore is dangerous!

  realGLboolean depthWriteMask = 0;
  gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
  MOZ_ASSERT(depthWriteMask == mDepthWriteMask);

  GLfloat depthClearValue = 0.0f;
  gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
  MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue));

  const int maxStencilBits = 8;
  const GLuint maxStencilBitsMask = (1 << maxStencilBits) - 1;
  AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE,
                               maxStencilBitsMask, mStencilClearValue);

  // GLES 3.0.4, $4.1.4, p177:
  //   [...] the front and back stencil mask are both set to the value `2^s -
  //   1`, where `s` is greater than or equal to the number of bits in the
  //   deepest stencil buffer supported by the GL implementation.
  AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,
                               maxStencilBitsMask, mStencilValueMaskFront);
  AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK,
                               maxStencilBitsMask, mStencilValueMaskBack);

  AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,
                               maxStencilBitsMask, mStencilWriteMaskFront);
  AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,
                               maxStencilBitsMask, mStencilWriteMaskBack);

  // Viewport
  GLint int4[4] = {0, 0, 0, 0};
  gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4);
  MOZ_ASSERT(int4[0] == mViewportX && int4[1] == mViewportY &&
             int4[2] == mViewportWidth && int4[3] == mViewportHeight);

  AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT,
                         mPixelStore_PackAlignment);
  AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT,
                         mPixelStore_UnpackAlignment);

  if (IsWebGL2()) {
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT,
                           mPixelStore_UnpackImageHeight);
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES,
                           mPixelStore_UnpackSkipImages);
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH,
                           mPixelStore_UnpackRowLength);
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS,
                           mPixelStore_UnpackSkipRows);
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS,
                           mPixelStore_UnpackSkipPixels);
    AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH,
                           mPixelStore_PackRowLength);
    AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS,
                           mPixelStore_PackSkipRows);
    AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS,
                           mPixelStore_PackSkipPixels);
  }

  MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError()));
#endif
}
예제 #18
0
JS::Value
WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
{
    if (IsContextLost())
        return JS::NullValue();

    MakeContextCurrent();

    if (MinCapabilityMode()) {
        switch(pname) {
            ////////////////////////////
            // Single-value params

            // int
            case LOCAL_GL_MAX_VERTEX_ATTRIBS:
                return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS);

            case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
                return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS);

            case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
                return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS);

            case LOCAL_GL_MAX_VARYING_VECTORS:
                return JS::Int32Value(MINVALUE_GL_MAX_VARYING_VECTORS);

            case LOCAL_GL_MAX_TEXTURE_SIZE:
                return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_SIZE);

            case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
                return JS::Int32Value(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE);

            case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
                return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS);

            case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
                return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);

            case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
                return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE);

            default:
                // Return the real value; we're not overriding this one
                break;
        }
    }

    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
        if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
            return JS::Int32Value(mImplMaxColorAttachments);

        } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
            return JS::Int32Value(mImplMaxDrawBuffers);

        } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
                   pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mImplMaxDrawBuffers))
        {
            GLint iv = 0;
            gl->fGetIntegerv(pname, &iv);

            if (mBoundDrawFramebuffer)
                return JS::Int32Value(iv);

            const GLint index = (pname - LOCAL_GL_DRAW_BUFFER0);
            if (iv == LOCAL_GL_COLOR_ATTACHMENT0 + index)
                return JS::Int32Value(LOCAL_GL_BACK);

            return JS::Int32Value(LOCAL_GL_NONE);
        }
    }

    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
        if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
            WebGLVertexArray* vao =
                (mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
            return WebGLObjectAsJSValue(cx, vao, rv);
        }
    }

    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
        if (pname == LOCAL_GL_TIMESTAMP_EXT) {
            GLuint64 iv = 0;
            gl->fGetInteger64v(pname, (GLint64*) &iv);
            // TODO: JS doesn't support 64-bit integers. Be lossy and
            // cast to double (53 bits)
            return JS::NumberValue(static_cast<double>(iv));
        } else if (pname == LOCAL_GL_GPU_DISJOINT_EXT) {
            // When disjoint isn't supported, leave as false.
            realGLboolean disjoint = LOCAL_GL_FALSE;
            if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
                gl->fGetBooleanv(pname, &disjoint);
            }
            return JS::BooleanValue(bool(disjoint));
        }
    }

    // Privileged string params exposed by WEBGL_debug_renderer_info.
    // The privilege check is done in WebGLContext::IsExtensionSupported.
    // So here we just have to check that the extension is enabled.
    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) {
        switch (pname) {
        case UNMASKED_VENDOR_WEBGL:
        case UNMASKED_RENDERER_WEBGL:
            {
                const char* overridePref = nullptr;
                GLenum driverEnum = LOCAL_GL_NONE;

                switch (pname) {
                case UNMASKED_RENDERER_WEBGL:
                    overridePref = "webgl.renderer-string-override";
                    driverEnum = LOCAL_GL_RENDERER;
                    break;
                case UNMASKED_VENDOR_WEBGL:
                    overridePref = "webgl.vendor-string-override";
                    driverEnum = LOCAL_GL_VENDOR;
                    break;
                default:
                    MOZ_CRASH("bad `pname`");
                }

                bool hasRetVal = false;

                nsAutoString ret;
                if (overridePref) {
                    nsresult res = Preferences::GetString(overridePref, &ret);
                    if (NS_SUCCEEDED(res) && ret.Length() > 0)
                        hasRetVal = true;
                }

                if (!hasRetVal) {
                    const char* chars = reinterpret_cast<const char*>(gl->fGetString(driverEnum));
                    ret = NS_ConvertASCIItoUTF16(chars);
                    hasRetVal = true;
                }

                return StringValue(cx, ret, rv);
            }
        }
    }

    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
        if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
            GLint i = 0;
            gl->fGetIntegerv(pname, &i);
            return JS::Int32Value(i);
        }
    }

    if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
        if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) {
            GLfloat f = 0.f;
            gl->fGetFloatv(pname, &f);
            return JS::NumberValue(f);
        }
    }

    switch (pname) {
        //
        // String params
        //
        case LOCAL_GL_VENDOR:
        case LOCAL_GL_RENDERER:
            return StringValue(cx, "Mozilla", rv);
        case LOCAL_GL_VERSION:
            return StringValue(cx, "WebGL 1.0", rv);
        case LOCAL_GL_SHADING_LANGUAGE_VERSION:
            return StringValue(cx, "WebGL GLSL ES 1.0", rv);

        ////////////////////////////////
        // Single-value params

        // unsigned int
        case LOCAL_GL_CULL_FACE_MODE:
        case LOCAL_GL_FRONT_FACE:
        case LOCAL_GL_ACTIVE_TEXTURE:
        case LOCAL_GL_STENCIL_FUNC:
        case LOCAL_GL_STENCIL_FAIL:
        case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
        case LOCAL_GL_STENCIL_PASS_DEPTH_PASS:
        case LOCAL_GL_STENCIL_BACK_FUNC:
        case LOCAL_GL_STENCIL_BACK_FAIL:
        case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL:
        case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
        case LOCAL_GL_DEPTH_FUNC:
        case LOCAL_GL_BLEND_SRC_RGB:
        case LOCAL_GL_BLEND_SRC_ALPHA:
        case LOCAL_GL_BLEND_DST_RGB:
        case LOCAL_GL_BLEND_DST_ALPHA:
        case LOCAL_GL_BLEND_EQUATION_RGB:
        case LOCAL_GL_BLEND_EQUATION_ALPHA:
        case LOCAL_GL_GENERATE_MIPMAP_HINT: {
            GLint i = 0;
            gl->fGetIntegerv(pname, &i);
            return JS::NumberValue(uint32_t(i));
        }
        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
            if (mBoundReadFramebuffer) {
                nsCString fbStatusInfoIgnored;
                const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
                                          " complete before querying"
                                          " IMPLEMENTATION_COLOR_READ_TYPE.");
                    return JS::NullValue();
                }
            }

            GLint i = 0;
            if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                gl->fGetIntegerv(pname, &i);
            } else {
                i = LOCAL_GL_UNSIGNED_BYTE;
            }

            return JS::NumberValue(uint32_t(i));
        }
        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
            if (mBoundReadFramebuffer) {
                nsCString fbStatusInfoIgnored;
                const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfoIgnored);
                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
                                          " complete before querying"
                                          " IMPLEMENTATION_COLOR_READ_FORMAT.");
                    return JS::NullValue();
                }
            }

            GLint i = 0;
            if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                gl->fGetIntegerv(pname, &i);
            } else {
                i = LOCAL_GL_RGBA;
            }

            // OpenGL ES 3.0.4 p112 Table 3.2 shows that read format SRGB_ALPHA is
            // not supported. And if internal format of fbo is SRGB8_ALPHA8, then
            // IMPLEMENTATION_COLOR_READ_FORMAT is SRGB_ALPHA which is not supported
            // by ReadPixels. So, just return RGBA here.
            if (i == LOCAL_GL_SRGB_ALPHA)
                i = LOCAL_GL_RGBA;

            return JS::NumberValue(uint32_t(i));
        }
        // int
        case LOCAL_GL_STENCIL_REF:
        case LOCAL_GL_STENCIL_BACK_REF: {
            GLint stencilBits = 0;
            if (!GetStencilBits(&stencilBits))
                return JS::NullValue();

            // Assuming stencils have 8 bits
            const GLint stencilMask = (1 << stencilBits) - 1;

            GLint refValue = 0;
            gl->fGetIntegerv(pname, &refValue);

            return JS::Int32Value(refValue & stencilMask);
        }
        case LOCAL_GL_STENCIL_BITS: {
            GLint stencilBits = 0;
            GetStencilBits(&stencilBits);
            return JS::Int32Value(stencilBits);
        }
        case LOCAL_GL_STENCIL_CLEAR_VALUE:
        case LOCAL_GL_UNPACK_ALIGNMENT:
        case LOCAL_GL_PACK_ALIGNMENT:
        case LOCAL_GL_SUBPIXEL_BITS:
        case LOCAL_GL_SAMPLE_BUFFERS:
        case LOCAL_GL_SAMPLES:
        case LOCAL_GL_MAX_VERTEX_ATTRIBS:
        case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
        case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
        case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
        case LOCAL_GL_RED_BITS:
        case LOCAL_GL_GREEN_BITS:
        case LOCAL_GL_BLUE_BITS: {
            GLint i = 0;
            gl->fGetIntegerv(pname, &i);
            return JS::Int32Value(i);
        }
        case LOCAL_GL_DEPTH_BITS: {
            GLint i = 0;
            if (!mNeedsFakeNoDepth) {
                gl->fGetIntegerv(pname, &i);
            }
            return JS::Int32Value(i);
        }
        case LOCAL_GL_ALPHA_BITS: {
            GLint i = 0;
            if (!mNeedsFakeNoAlpha) {
                gl->fGetIntegerv(pname, &i);
            }
            return JS::Int32Value(i);
        }
        case LOCAL_GL_MAX_TEXTURE_SIZE:
            return JS::Int32Value(mImplMaxTextureSize);

        case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
            return JS::Int32Value(mImplMaxCubeMapTextureSize);

        case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
            return JS::Int32Value(mImplMaxRenderbufferSize);

        case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
            return JS::Int32Value(mGLMaxVertexUniformVectors);

        case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
            return JS::Int32Value(mGLMaxFragmentUniformVectors);

        case LOCAL_GL_MAX_VARYING_VECTORS:
            return JS::Int32Value(mGLMaxVaryingVectors);

        case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
            uint32_t length = mCompressedTextureFormats.Length();
            JSObject* obj = dom::Uint32Array::Create(cx, this, length,
                                                     mCompressedTextureFormats.Elements());
            if (!obj) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return JS::ObjectOrNullValue(obj);
        }

        // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
        // javascript integer values. We just return them as doubles and javascript doesn't care.
        case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
            return JS::DoubleValue(mStencilValueMaskBack); // pass as FP value to allow large values such as 2^32-1.

        case LOCAL_GL_STENCIL_BACK_WRITEMASK:
            return JS::DoubleValue(mStencilWriteMaskBack);

        case LOCAL_GL_STENCIL_VALUE_MASK:
            return JS::DoubleValue(mStencilValueMaskFront);

        case LOCAL_GL_STENCIL_WRITEMASK:
            return JS::DoubleValue(mStencilWriteMaskFront);

        // float
        case LOCAL_GL_DEPTH_CLEAR_VALUE:
        case LOCAL_GL_LINE_WIDTH:
        case LOCAL_GL_POLYGON_OFFSET_FACTOR:
        case LOCAL_GL_POLYGON_OFFSET_UNITS:
        case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
            GLfloat f = 0.f;
            gl->fGetFloatv(pname, &f);
            return JS::DoubleValue(f);
        }

        // bool
        case LOCAL_GL_BLEND:
        case LOCAL_GL_DEPTH_TEST:
        case LOCAL_GL_STENCIL_TEST:
        case LOCAL_GL_CULL_FACE:
        case LOCAL_GL_DITHER:
        case LOCAL_GL_POLYGON_OFFSET_FILL:
        case LOCAL_GL_SCISSOR_TEST:
        case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
        case LOCAL_GL_DEPTH_WRITEMASK: {
            realGLboolean b = 0;
            gl->fGetBooleanv(pname, &b);
            return JS::BooleanValue(bool(b));
        }

        // bool, WebGL-specific
        case UNPACK_FLIP_Y_WEBGL:
            return JS::BooleanValue(mPixelStore_FlipY);
        case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
            return JS::BooleanValue(mPixelStore_PremultiplyAlpha);

        // uint, WebGL-specific
        case UNPACK_COLORSPACE_CONVERSION_WEBGL:
            return JS::NumberValue(uint32_t(mPixelStore_ColorspaceConversion));

        ////////////////////////////////
        // Complex values

        // 2 floats
        case LOCAL_GL_DEPTH_RANGE:
        case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
        case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
            GLfloat fv[2] = { 0 };
            gl->fGetFloatv(pname, fv);
            JSObject* obj = dom::Float32Array::Create(cx, this, 2, fv);
            if (!obj) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return JS::ObjectOrNullValue(obj);
        }

        // 4 floats
        case LOCAL_GL_COLOR_CLEAR_VALUE:
        case LOCAL_GL_BLEND_COLOR: {
            GLfloat fv[4] = { 0 };
            gl->fGetFloatv(pname, fv);
            JSObject* obj = dom::Float32Array::Create(cx, this, 4, fv);
            if (!obj) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return JS::ObjectOrNullValue(obj);
        }

        // 2 ints
        case LOCAL_GL_MAX_VIEWPORT_DIMS: {
            GLint iv[2] = { 0 };
            gl->fGetIntegerv(pname, iv);
            JSObject* obj = dom::Int32Array::Create(cx, this, 2, iv);
            if (!obj) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return JS::ObjectOrNullValue(obj);
        }

        // 4 ints
        case LOCAL_GL_SCISSOR_BOX:
        case LOCAL_GL_VIEWPORT: {
            GLint iv[4] = { 0 };
            gl->fGetIntegerv(pname, iv);
            JSObject* obj = dom::Int32Array::Create(cx, this, 4, iv);
            if (!obj) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return JS::ObjectOrNullValue(obj);
        }

        // 4 bools
        case LOCAL_GL_COLOR_WRITEMASK: {
            realGLboolean gl_bv[4] = { 0 };
            gl->fGetBooleanv(pname, gl_bv);
            bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]),
                             bool(gl_bv[2]), bool(gl_bv[3]) };
            JS::Rooted<JS::Value> arr(cx);
            if (!dom::ToJSValue(cx, vals, &arr)) {
                rv = NS_ERROR_OUT_OF_MEMORY;
            }
            return arr;
        }

        case LOCAL_GL_ARRAY_BUFFER_BINDING: {
            return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
        }

        case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
            return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv);
        }

        case LOCAL_GL_RENDERBUFFER_BINDING: {
            return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
        }

        // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
        case LOCAL_GL_FRAMEBUFFER_BINDING: {
            return WebGLObjectAsJSValue(cx, mBoundDrawFramebuffer.get(), rv);
        }

        case LOCAL_GL_CURRENT_PROGRAM: {
            return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
        }

        case LOCAL_GL_TEXTURE_BINDING_2D: {
            return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
        }

        case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: {
            return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv);
        }

        default:
            break;
    }

    ErrorInvalidEnumInfo("getParameter: parameter", pname);
    return JS::NullValue();
}
void
WebGLContext::VertexAttribAnyPointer(const char* funcName, bool isFuncInt, GLuint index,
                                     GLint size, GLenum type, bool normalized,
                                     GLsizei stride, WebGLintptr byteOffset)
{
    if (IsContextLost())
        return;

    if (!ValidateAttribIndex(index, funcName))
        return;

    ////

    if (size < 1 || size > 4) {
        ErrorInvalidValue("%s: invalid element size", funcName);
        return;
    }

    // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
    if (stride < 0 || stride > 255) {
        ErrorInvalidValue("%s: negative or too large stride", funcName);
        return;
    }

    if (byteOffset < 0) {
        ErrorInvalidValue("%s: negative offset", funcName);
        return;
    }

    ////

    bool isTypeValid = true;
    uint8_t typeAlignment;
    switch (type) {
    // WebGL 1:
    case LOCAL_GL_BYTE:
    case LOCAL_GL_UNSIGNED_BYTE:
        typeAlignment = 1;
        break;

    case LOCAL_GL_SHORT:
    case LOCAL_GL_UNSIGNED_SHORT:
        typeAlignment = 2;
        break;

    case LOCAL_GL_FLOAT:
        if (isFuncInt) {
            isTypeValid = false;
        }
        typeAlignment = 4;
        break;

    // WebGL 2:
    case LOCAL_GL_INT:
    case LOCAL_GL_UNSIGNED_INT:
        if (!IsWebGL2()) {
            isTypeValid = false;
        }
        typeAlignment = 4;
        break;

    case LOCAL_GL_HALF_FLOAT:
        if (isFuncInt || !IsWebGL2()) {
            isTypeValid = false;
        }
        typeAlignment = 2;
        break;

    case LOCAL_GL_FIXED:
        if (isFuncInt || !IsWebGL2()) {
            isTypeValid = false;
        }
        typeAlignment = 4;
        break;

    case LOCAL_GL_INT_2_10_10_10_REV:
    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
        if (isFuncInt || !IsWebGL2()) {
            isTypeValid = false;
            break;
        }
        if (size != 4) {
            ErrorInvalidOperation("%s: size must be 4 for this type.", funcName);
            return;
        }
        typeAlignment = 4;
        break;

    default:
        isTypeValid = false;
        break;
    }
    if (!isTypeValid) {
        ErrorInvalidEnumArg(funcName, "type", type);
        return;
    }

    ////

    // `alignment` should always be a power of two.
    MOZ_ASSERT(IsPowerOfTwo(typeAlignment));
    const GLsizei typeAlignmentMask = typeAlignment - 1;

    if (stride & typeAlignmentMask ||
        byteOffset & typeAlignmentMask)
    {
        ErrorInvalidOperation("%s: `stride` and `byteOffset` must satisfy the alignment"
                              " requirement of `type`.",
                              funcName);
        return;
    }

    ////

    const auto& buffer = mBoundArrayBuffer;
    if (!buffer && byteOffset) {
        ErrorInvalidOperation("%s: If ARRAY_BUFFER is null, byteOffset must be zero.",
                              funcName);
        return;
    }

    ////

    gl->MakeCurrent();
    if (isFuncInt) {
        gl->fVertexAttribIPointer(index, size, type, stride,
                                  reinterpret_cast<void*>(byteOffset));
    } else {
        gl->fVertexAttribPointer(index, size, type, normalized, stride,
                                 reinterpret_cast<void*>(byteOffset));
    }

    WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
    vd.VertexAttribPointer(isFuncInt, buffer, size, type, normalized, stride, byteOffset);

    InvalidateBufferFetching();
}
예제 #20
0
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
                                 WebGLintptr byteOffset, GLsizei primcount,
                                 const char* info, GLuint* out_upperBound)
{
    if (count < 0 || byteOffset < 0) {
        ErrorInvalidValue("%s: negative count or offset", info);
        return false;
    }

    if (primcount < 0) {
        ErrorInvalidValue("%s: negative primcount", info);
        return false;
    }

    if (!ValidateStencilParamsForDrawCall()) {
        return false;
    }

    // If count is 0, there's nothing to do.
    if (count == 0 || primcount == 0)
        return false;

    uint8_t bytesPerElem = 0;
    switch (type) {
    case LOCAL_GL_UNSIGNED_BYTE:
        bytesPerElem = 1;
        break;

    case LOCAL_GL_UNSIGNED_SHORT:
        bytesPerElem = 2;
        break;

    case LOCAL_GL_UNSIGNED_INT:
        if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
            bytesPerElem = 4;
        }
        break;
    }

    if (!bytesPerElem) {
        ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
        return false;
    }

    if (byteOffset % bytesPerElem != 0) {
        ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
                              info);
        return false;
    }

    const GLsizei first = byteOffset / bytesPerElem;
    const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);

    if (!checked_byteCount.isValid()) {
        ErrorInvalidValue("%s: overflow in byteCount", info);
        return false;
    }

    // Any checks below this depend on a program being available.
    if (!mCurrentProgram) {
        ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
        return false;
    }

    if (!mBoundVertexArray->mElementArrayBuffer) {
        ErrorInvalidOperation("%s: must have element array buffer binding", info);
        return false;
    }

    WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;

    if (!elemArrayBuffer.ByteLength()) {
        ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
        return false;
    }

    CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;

    if (!checked_neededByteCount.isValid()) {
        ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
        return false;
    }

    if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
        ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
        return false;
    }

    if (!ValidateBufferFetching(info))
        return false;

    if (!mMaxFetchedVertices ||
        !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
    {
        ErrorInvalidOperation(
                              "%s: bound vertex attribute buffers do not have sufficient "
                              "size for given indices from the bound element array", info);
        return false;
    }

    if (uint32_t(primcount) > mMaxFetchedInstances) {
        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
        return false;
    }

    // Bug 1008310 - Check if buffer has been used with a different previous type
    if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
        GenerateWarning("%s: bound element array buffer previously used with a type other than "
                        "%s, this will affect performance.",
                        info,
                        WebGLContext::EnumName(type));
    }

    MOZ_ASSERT(gl->IsCurrent());

    if (mBoundDrawFramebuffer) {
        if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
            return false;
    } else {
        ClearBackbufferIfNeeded();
    }

    if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
        return false;
    }

    return true;
}
bool
WebGLContext::InitAndValidateGL()
{
    if (!gl)
        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)
        return false;

    GLenum error = gl->fGetError();
    if (error != LOCAL_GL_NO_ERROR) {
        GenerateWarning("GL error 0x%x occurred during OpenGL context"
                        " initialization, before WebGL initialization!", error);
        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;

    /*
    // 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;

    // 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;
    mBoundTransformFeedbackBuffer = nullptr;
    mCurrentProgram = nullptr;

    mBoundDrawFramebuffer = nullptr;
    mBoundReadFramebuffer = nullptr;
    mBoundRenderbuffer = nullptr;

    MakeContextCurrent();

    // For OpenGL compat. profiles, we always keep vertex attrib 0 array enabled.
    if (gl->IsCompatibilityProfile())
        gl->fEnableVertexAttribArray(0);

    if (MinCapabilityMode())
        mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
    else
        gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);

    if (mGLMaxVertexAttribs < 8) {
        GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
                        mGLMaxVertexAttribs);
        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
        gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);

    if (mGLMaxTextureUnits < 8) {
        GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!",
                        mGLMaxTextureUnits);
        return false;
    }

    mBound2DTextures.SetLength(mGLMaxTextureUnits);
    mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
    mBound3DTextures.SetLength(mGLMaxTextureUnits);
    mBound2DArrayTextures.SetLength(mGLMaxTextureUnits);
    mBoundSamplers.SetLength(mGLMaxTextureUnits);

    ////////////////

    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_PointSize is always available in ES2 GLSL, but has to be
        // specifically enabled on desktop GLSL.
        gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);

        /* gl_PointCoord is always available in ES2 GLSL and in newer desktop
         * GLSL versions, but apparently not in OpenGL 2 and apparently not (due
         * to a driver bug) on certain NVIDIA setups. See:
         *   http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
         *
         * Note that this used to cause crashes on old ATI drivers... Hopefully
         * not a significant anymore. See bug 602183.
         */
        gl->fEnable(LOCAL_GL_POINT_SPRITE);
    }

#ifdef XP_MACOSX
    if (gl->WorkAroundDriverBugs() &&
        gl->Vendor() == gl::GLVendor::ATI &&
        !nsCocoaFeatures::IsAtLeastVersion(10,9))
    {
        // The Mac ATI driver, in all known OSX version up to and including
        // 10.8, renders points sprites upside-down. (Apple bug 11778921)
        gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
                             LOCAL_GL_LOWER_LEFT);
    }
#endif

    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()) {
        GenerateWarning("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) {
        GenerateWarning("GL error 0x%x occurred during WebGL context"
                        " initialization!", error);
        return false;
    }

    if (IsWebGL2() &&
        !InitWebGL2())
    {
        // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
        return false;
    }

    // Default value for all disabled vertex attributes is [0, 0, 0, 1]
    mVertexAttribType = MakeUnique<GLenum[]>(mGLMaxVertexAttribs);
    for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
        mVertexAttribType[index] = LOCAL_GL_FLOAT;
        VertexAttrib4f(index, 0, 0, 0, 1);
    }

    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()) {
        MakeContextCurrent();
        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;

    return true;
}
예제 #22
0
void
WebGLContext::AssertCachedBindings()
{
#ifdef DEBUG
    MakeContextCurrent();

    GetAndFlushUnderlyingGLErrors();

    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
        GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
        AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
    }

    // Framebuffers
    if (IsWebGL2()) {
        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
                                             : 0;
        AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);

        bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0;
        AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
    } else {
        MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
                                             : 0;
        AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
    }

    GLint stencilBits = 0;
    if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
        const GLuint stencilRefMask = (1 << stencilBits) - 1;

        AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF,      stencilRefMask, mStencilRefFront);
        AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
    }

    // Program
    GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
    AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);

    // Textures
    GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
    AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);

    WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
    bound = curTex ? curTex->mGLName : 0;
    AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound);

    curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP);
    bound = curTex ? curTex->mGLName : 0;
    AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound);

    // Buffers
    bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0;
    AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound);

    MOZ_ASSERT(mBoundVertexArray);
    WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer;
    bound = curBuff ? curBuff->mGLName : 0;
    AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound);

    MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
#endif

    // We do not check the renderbuffer binding, because we never rely on it matching.
}
예제 #23
0
bool
WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
    if (mDisableExtensions)
        return false;

    // In alphabetical order
    switch (ext) {
    // ANGLE_
    case WebGLExtensionID::ANGLE_instanced_arrays:
        return WebGLExtensionInstancedArrays::IsSupported(this);

    // EXT_
    case WebGLExtensionID::EXT_blend_minmax:
        return WebGLExtensionBlendMinMax::IsSupported(this);
    case WebGLExtensionID::EXT_color_buffer_half_float:
        return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
    case WebGLExtensionID::EXT_frag_depth:
        return WebGLExtensionFragDepth::IsSupported(this);
    case WebGLExtensionID::EXT_shader_texture_lod:
        return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
    case WebGLExtensionID::EXT_sRGB:
        return WebGLExtensionSRGB::IsSupported(this);
    case WebGLExtensionID::EXT_texture_filter_anisotropic:
        return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);

    // OES_
    case WebGLExtensionID::OES_element_index_uint:
        return gl->IsSupported(gl::GLFeature::element_index_uint);
    case WebGLExtensionID::OES_standard_derivatives:
        return gl->IsSupported(gl::GLFeature::standard_derivatives);
    case WebGLExtensionID::OES_texture_float:
        return gl->IsSupported(gl::GLFeature::texture_float);
    case WebGLExtensionID::OES_texture_float_linear:
        return gl->IsSupported(gl::GLFeature::texture_float_linear);
    case WebGLExtensionID::OES_texture_half_float:
        // If we have Feature::texture_half_float, we must not be on ES2
        // and need to translate HALF_FLOAT_OES -> HALF_FLOAT.  We do that
        // right before making the relevant calls.
        return gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float) ||
               gl->IsSupported(gl::GLFeature::texture_half_float);

    case WebGLExtensionID::OES_texture_half_float_linear:
        return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
    case WebGLExtensionID::OES_vertex_array_object:
        return true;

    // WEBGL_
    case WebGLExtensionID::WEBGL_color_buffer_float:
        return WebGLExtensionColorBufferFloat::IsSupported(this);
    case WebGLExtensionID::WEBGL_compressed_texture_atc:
        return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
    case WebGLExtensionID::WEBGL_compressed_texture_etc1:
        return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
    case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
        return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
        if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
            return true;

        return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
               gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
               gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);

    case WebGLExtensionID::WEBGL_debug_renderer_info:
        return Preferences::GetBool("webgl.enable-debug-renderer-info", false);

    case WebGLExtensionID::WEBGL_depth_texture:
        // WEBGL_depth_texture supports DEPTH_STENCIL textures
        if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
            return false;

        return gl->IsSupported(gl::GLFeature::depth_texture) ||
               gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
    case WebGLExtensionID::WEBGL_draw_buffers:
        return WebGLExtensionDrawBuffers::IsSupported(this);
    case WebGLExtensionID::WEBGL_lose_context:
        // We always support this extension.
        return true;

    default:
        // For warnings-as-errors.
        break;
    }

    if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) {
        switch (ext) {
        case WebGLExtensionID::EXT_disjoint_timer_query:
            return WebGLExtensionDisjointTimerQuery::IsSupported(this);
        default:
            // For warnings-as-errors.
            break;
        }
    }

    return false;
}
예제 #24
0
void
WebGLContext::AssertCachedGlobalState()
{
#ifdef DEBUG
    MakeContextCurrent();

    GetAndFlushUnderlyingGLErrors();

    ////////////////

    // Draw state
    MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled);
    MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
    MOZ_ASSERT_IF(IsWebGL2(),
                  gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
    MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
    MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_STENCIL_TEST) == mStencilTestEnabled);

    realGLboolean colorWriteMask[4] = {0, 0, 0, 0};
    gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
    MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
               colorWriteMask[1] == mColorWriteMask[1] &&
               colorWriteMask[2] == mColorWriteMask[2] &&
               colorWriteMask[3] == mColorWriteMask[3]);

    GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
    gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
    MOZ_ASSERT(IsCacheCorrect(mColorClearValue[0], colorClearValue[0]) &&
               IsCacheCorrect(mColorClearValue[1], colorClearValue[1]) &&
               IsCacheCorrect(mColorClearValue[2], colorClearValue[2]) &&
               IsCacheCorrect(mColorClearValue[3], colorClearValue[3]));

    realGLboolean depthWriteMask = 0;
    gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
    MOZ_ASSERT(depthWriteMask == mDepthWriteMask);

    GLfloat depthClearValue = 0.0f;
    gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
    MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue));

    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);

    // GLES 3.0.4, $4.1.4, p177:
    //   [...] the front and back stencil mask are both set to the value `2^s - 1`, where
    //   `s` is greater than or equal to the number of bits in the deepest stencil buffer
    //   supported by the GL implementation.
    const int maxStencilBits = 8;
    const GLuint maxStencilBitsMask = (1 << maxStencilBits) - 1;
    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,      maxStencilBitsMask, mStencilValueMaskFront);
    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, maxStencilBitsMask, mStencilValueMaskBack);

    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,       maxStencilBitsMask, mStencilWriteMaskFront);
    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,  maxStencilBitsMask, mStencilWriteMaskBack);

    // Viewport
    GLint int4[4] = {0, 0, 0, 0};
    gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4);
    MOZ_ASSERT(int4[0] == mViewportX &&
               int4[1] == mViewportY &&
               int4[2] == mViewportWidth &&
               int4[3] == mViewportHeight);

    AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment);
    AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);

    if (IsWebGL2()) {
        AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT, mPixelStore_UnpackImageHeight);
        AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES , mPixelStore_UnpackSkipImages);
        AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH  , mPixelStore_UnpackRowLength);
        AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS   , mPixelStore_UnpackSkipRows);
        AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS , mPixelStore_UnpackSkipPixels);
        AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH    , mPixelStore_PackRowLength);
        AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS     , mPixelStore_PackSkipRows);
        AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS   , mPixelStore_PackSkipPixels);
    }

    MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
#endif
}
예제 #25
0
bool
WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
    if (mDisableExtensions)
        return false;

    // Extensions for both WebGL 1 and 2.
    switch (ext) {
    // In alphabetical order
    // EXT_
    case WebGLExtensionID::EXT_disjoint_timer_query:
        return WebGLExtensionDisjointTimerQuery::IsSupported(this);
    case WebGLExtensionID::EXT_texture_filter_anisotropic:
        return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);

    // OES_
    case WebGLExtensionID::OES_texture_float_linear:
        return gl->IsSupported(gl::GLFeature::texture_float_linear);

    // WEBGL_
    case WebGLExtensionID::WEBGL_compressed_texture_astc:
        return WebGLExtensionCompressedTextureASTC::IsSupported(this);
    case WebGLExtensionID::WEBGL_compressed_texture_atc:
        return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
    case WebGLExtensionID::WEBGL_compressed_texture_etc:
        return gl->IsSupported(gl::GLFeature::ES3_compatibility) &&
               !gl->IsANGLE();
    case WebGLExtensionID::WEBGL_compressed_texture_etc1:
        return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture) &&
               !gl->IsANGLE();
    case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
        return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
        return WebGLExtensionCompressedTextureS3TC::IsSupported(this);
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
        return WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported(this);
    case WebGLExtensionID::WEBGL_debug_renderer_info:
        return Preferences::GetBool("webgl.enable-debug-renderer-info", false);
    case WebGLExtensionID::WEBGL_debug_shaders:
        return !nsContentUtils::ShouldResistFingerprinting();
    case WebGLExtensionID::WEBGL_lose_context:
        // We always support this extension.
        return true;

    default:
        // For warnings-as-errors.
        break;
    }

    if (IsWebGL2()) {
        // WebGL2-only extensions
        switch (ext) {
        // EXT_
        case WebGLExtensionID::EXT_color_buffer_float:
            return WebGLExtensionEXTColorBufferFloat::IsSupported(this);

        default:
            // For warnings-as-errors.
            break;
        }
    } else {
        // WebGL1-only extensions
        switch (ext) {
        // ANGLE_
        case WebGLExtensionID::ANGLE_instanced_arrays:
            return WebGLExtensionInstancedArrays::IsSupported(this);

        // EXT_
        case WebGLExtensionID::EXT_blend_minmax:
            return WebGLExtensionBlendMinMax::IsSupported(this);
        case WebGLExtensionID::EXT_color_buffer_half_float:
            return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
        case WebGLExtensionID::EXT_frag_depth:
            return WebGLExtensionFragDepth::IsSupported(this);
        case WebGLExtensionID::EXT_shader_texture_lod:
            return gl->IsSupported(gl::GLFeature::shader_texture_lod);
        case WebGLExtensionID::EXT_sRGB:
            return WebGLExtensionSRGB::IsSupported(this);

        // OES_
        case WebGLExtensionID::OES_element_index_uint:
            return gl->IsSupported(gl::GLFeature::element_index_uint);
        case WebGLExtensionID::OES_standard_derivatives:
            return gl->IsSupported(gl::GLFeature::standard_derivatives);
        case WebGLExtensionID::OES_texture_float:
            return WebGLExtensionTextureFloat::IsSupported(this);
        case WebGLExtensionID::OES_texture_half_float:
            return WebGLExtensionTextureHalfFloat::IsSupported(this);
        case WebGLExtensionID::OES_texture_half_float_linear:
            return gl->IsSupported(gl::GLFeature::texture_half_float_linear);

        case WebGLExtensionID::OES_vertex_array_object:
            return true;

        // WEBGL_
        case WebGLExtensionID::WEBGL_color_buffer_float:
            return WebGLExtensionColorBufferFloat::IsSupported(this);
        case WebGLExtensionID::WEBGL_depth_texture:
            // WEBGL_depth_texture supports DEPTH_STENCIL textures
            if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
                return false;

            return gl->IsSupported(gl::GLFeature::depth_texture) ||
                   gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
        case WebGLExtensionID::WEBGL_draw_buffers:
            return WebGLExtensionDrawBuffers::IsSupported(this);
        default:
            // For warnings-as-errors.
            break;
        }

        if (gfxPrefs::WebGLDraftExtensionsEnabled()) {
            /*
            switch (ext) {
            default:
                // For warnings-as-errors.
                break;
            }
            */
        }
    }

    return false;
}
예제 #26
0
bool
WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
                                 GLenum type, WebGLintptr byteOffset,
                                 GLsizei instanceCount)
{
    if (!ValidateDrawModeEnum(mode, funcName))
        return false;

    if (mBoundTransformFeedback &&
        mBoundTransformFeedback->mIsActive &&
        !mBoundTransformFeedback->mIsPaused)
    {
        ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
                              " transform feedback.",
                              funcName);
        return false;
    }

    if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
        !ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
        !ValidateNonNegative(funcName, "instanceCount", instanceCount))
    {
        return false;
    }

    if (!ValidateStencilParamsForDrawCall())
        return false;

    if (!vertCount || !instanceCount)
        return false; // No error, just early out.

    uint8_t bytesPerElem = 0;
    switch (type) {
    case LOCAL_GL_UNSIGNED_BYTE:
        bytesPerElem = 1;
        break;

    case LOCAL_GL_UNSIGNED_SHORT:
        bytesPerElem = 2;
        break;

    case LOCAL_GL_UNSIGNED_INT:
        if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
            bytesPerElem = 4;
        }
        break;
    }

    if (!bytesPerElem) {
        ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
        return false;
    }

    if (byteOffset % bytesPerElem != 0) {
        ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
                              funcName);
        return false;
    }

    ////

    if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
        MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
        if (mPrimRestartTypeBytes != bytesPerElem) {
            mPrimRestartTypeBytes = bytesPerElem;

            const uint32_t ones = UINT32_MAX >> (32 - 8*mPrimRestartTypeBytes);
            gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART);
            gl->fPrimitiveRestartIndex(ones);
        }
예제 #27
0
JS::Value
WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
                              ErrorResult& rv)
{
    const char funcName[] = "getVertexAttrib";
    if (IsContextLost())
        return JS::NullValue();

    if (!ValidateAttribIndex(index, funcName))
        return JS::NullValue();

    MOZ_ASSERT(mBoundVertexArray);

    MakeContextCurrent();

    switch (pname) {
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
        return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].mBuf.get(), rv);

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Stride());

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Size());

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Type());

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
        if (IsWebGL2())
            return JS::BooleanValue(mBoundVertexArray->mAttribs[index].IntegerFunc());

        break;

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
        if (IsWebGL2() ||
            IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
        {
            return JS::Int32Value(mBoundVertexArray->mAttribs[index].mDivisor);
        }
        break;

    case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
        {
            JS::RootedObject obj(cx);
            switch (mGenericVertexAttribTypes[index]) {
            case LOCAL_GL_FLOAT:
                obj = GetVertexAttribFloat32Array(cx, index);
                break;

            case LOCAL_GL_INT:
                obj =  GetVertexAttribInt32Array(cx, index);
                break;

            case LOCAL_GL_UNSIGNED_INT:
                obj = GetVertexAttribUint32Array(cx, index);
                break;
            }

            if (!obj)
                rv.Throw(NS_ERROR_OUT_OF_MEMORY);
            return JS::ObjectOrNullValue(obj);
        }

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
        return JS::BooleanValue(mBoundVertexArray->mAttribs[index].mEnabled);

    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
        return JS::BooleanValue(mBoundVertexArray->mAttribs[index].Normalized());

    default:
        break;
    }

    ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
    return JS::NullValue();
}
예제 #28
0
bool
WebGLContext::InitWebGL2(FailureReason* const out_failReason)
{
    MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");

    std::vector<gl::GLFeature> missingList;

    const auto fnGatherMissing = [&](gl::GLFeature cur) {
        if (!gl->IsSupported(cur)) {
            missingList.push_back(cur);
        }
    };

    const auto fnGatherMissing2 = [&](gl::GLFeature main, gl::GLFeature alt) {
        if (!gl->IsSupported(main) && !gl->IsSupported(alt)) {
            missingList.push_back(main);
        }
    };

    ////

    for (const auto& cur : kRequiredFeatures) {
        fnGatherMissing(cur);
    }

    // On desktop, we fake occlusion_query_boolean with occlusion_query if
    // necessary. (See WebGL2ContextQueries.cpp)
    fnGatherMissing2(gl::GLFeature::occlusion_query_boolean,
                     gl::GLFeature::occlusion_query);

#ifdef XP_MACOSX
    // On OSX, GL core profile is used. This requires texture swizzle
    // support to emulate legacy texture formats: ALPHA, LUMINANCE,
    // and LUMINANCE_ALPHA.
    fnGatherMissing(gl::GLFeature::texture_swizzle);
#endif

    fnGatherMissing2(gl::GLFeature::prim_restart_fixed,
                     gl::GLFeature::prim_restart);

    ////

    if (!missingList.empty()) {
        nsAutoCString exts;
        for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) {
            exts.AppendLiteral("\n  ");
            exts.Append(gl::GLContext::GetFeatureName(*itr));
        }

        const nsPrintfCString reason("WebGL 2 requires support for the following"
                                     " features: %s",
                                     exts.BeginReading());
        *out_failReason = FailureReason("FEATURE_FAILURE_WEBGL2_OCCL", reason);
        return false;
    }

    // we initialise WebGL 2 related stuff.
    gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                     &mGLMaxTransformFeedbackSeparateAttribs);
    gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
                     &mGLMaxUniformBufferBindings);

    mIndexedUniformBufferBindings.resize(mGLMaxUniformBufferBindings);

    mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
    mBoundTransformFeedback = mDefaultTransformFeedback;

    gl->fGenTransformFeedbacks(1, &mEmptyTFO);

    ////

    if (!gl->IsGLES()) {
        // Desktop OpenGL requires the following to be enabled in order to
        // support sRGB operations on framebuffers.
        gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
    }

    if (gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
        gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART_FIXED_INDEX);
    } else {
        MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
    }

    //////

    return true;
}
예제 #29
0
bool
WebGLContext::InitWebGL2()
{
    MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");

    // check OpenGL features
    if (!gl->IsSupported(gl::GLFeature::occlusion_query) &&
        !gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
    {
        // On desktop, we fake occlusion_query_boolean with occlusion_query if
        // necessary. (See WebGL2ContextQueries.cpp)
        GenerateWarning("WebGL 2 unavailable. Requires occlusion queries.");
        return false;
    }

    std::vector<gl::GLFeature> missingList;

    for (size_t i = 0; i < ArrayLength(kRequiredFeatures); i++) {
        if (!gl->IsSupported(kRequiredFeatures[i]))
            missingList.push_back(kRequiredFeatures[i]);
    }

#ifdef XP_MACOSX
    // On OSX, GL core profile is used. This requires texture swizzle
    // support to emulate legacy texture formats: ALPHA, LUMINANCE,
    // and LUMINANCE_ALPHA.
    if (!gl->IsSupported(gl::GLFeature::texture_swizzle))
        missingList.push_back(gl::GLFeature::texture_swizzle);
#endif

    if (missingList.size()) {
        nsAutoCString exts;
        for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) {
            exts.AppendLiteral("\n  ");
            exts.Append(gl::GLContext::GetFeatureName(*itr));
        }
        GenerateWarning("WebGL 2 unavailable. The following required features are"
                        " unavailible: %s", exts.BeginReading());
        return false;
    }

    // we initialise WebGL 2 related stuff.
    gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                     &mGLMaxTransformFeedbackSeparateAttribs);
    gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
                     &mGLMaxUniformBufferBindings);

    mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
    mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);

    mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
    mBoundTransformFeedback = mDefaultTransformFeedback;

    if (!gl->IsGLES()) {
        // Desktop OpenGL requires the following to be enabled in order to
        // support sRGB operations on framebuffers.
        gl->MakeCurrent();
        gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
    }

    return true;
}