Ejemplo n.º 1
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.
}
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;
}
Ejemplo n.º 3
0
bool
TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                              WebGLTexture* tex, TexImageTarget target, GLint level,
                              const webgl::DriverUnpackInfo* dui, GLint xOffset,
                              GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
                              GLenum* const out_error) const
{
    WebGLContext* webgl = tex->mContext;

    const auto format = FormatForPackingInfo(pi);
    const auto bytesPerPixel = webgl::BytesPerPixel(pi);

    const uint8_t* uploadPtr = mPtr;
    UniqueBuffer tempBuffer;

    do {
        if (!mIsClientData || !mPtr)
            break;

        if (!webgl->mPixelStore_FlipY &&
            !webgl->mPixelStore_PremultiplyAlpha)
        {
            break;
        }

        if (webgl->mPixelStore_UnpackImageHeight ||
            webgl->mPixelStore_UnpackSkipImages ||
            webgl->mPixelStore_UnpackRowLength ||
            webgl->mPixelStore_UnpackSkipRows ||
            webgl->mPixelStore_UnpackSkipPixels)
        {
            webgl->ErrorInvalidOperation("%s: Non-DOM-Element uploads with alpha-premult"
                                         " or y-flip do not support subrect selection.",
                                         funcName);
            return false;
        }

        webgl->GenerateWarning("%s: Alpha-premult and y-flip are deprecated for"
                               " non-DOM-Element uploads.",
                               funcName);

        const uint32_t rowLength = mWidth;
        const uint32_t rowCount = mHeight * mDepth;
        const auto stride = RoundUpToMultipleOf(rowLength * bytesPerPixel, mAlignment);
        if (!ConvertIfNeeded(webgl, funcName, rowLength, rowCount, format, mPtr, stride,
                             format, stride, &uploadPtr, &tempBuffer))
        {
            return false;
        }
    } while (false);

    //////

    const auto& gl = webgl->gl;

    bool useParanoidHandling = false;
    if (mNeedsExactUpload && webgl->mBoundPixelUnpackBuffer) {
        webgl->GenerateWarning("%s: Uploads from a buffer with a final row with a byte"
                               " count smaller than the row stride can incur extra"
                               " overhead.",
                               funcName);

        if (gl->WorkAroundDriverBugs()) {
            useParanoidHandling |= (gl->Vendor() == gl::GLVendor::NVIDIA);
        }
    }

    if (!useParanoidHandling) {
        if (webgl->mBoundPixelUnpackBuffer) {
            gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER,
                            webgl->mBoundPixelUnpackBuffer->mGLName);
        }

        *out_error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth, uploadPtr);

        if (webgl->mBoundPixelUnpackBuffer) {
            gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
        }
        return true;
    }

    //////

    MOZ_ASSERT(webgl->mBoundPixelUnpackBuffer);

    if (!isSubImage) {
        // Alloc first to catch OOMs.
        AssertUintParamCorrect(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
        *out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth, nullptr);
        if (*out_error)
            return true;
    }

    const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER,
                                 webgl->mBoundPixelUnpackBuffer);

    //////

    // Make our sometimes-implicit values explicit. Also this keeps them constant when we
    // ask for height=mHeight-1 and such.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
    gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);

    if (mDepth > 1) {
        *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
                                     zOffset, mWidth, mHeight, mDepth-1, uploadPtr);
    }

    // Skip the images we uploaded.
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages + mDepth - 1);

    if (mHeight > 1) {
        *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
                                     zOffset+mDepth-1, mWidth, mHeight-1, 1, uploadPtr);
    }

    const auto totalSkipRows = CheckedUint32(mSkipImages) * mImageHeight + mSkipRows;
    const auto totalFullRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight - 1;
    const auto tailOffsetRows = totalSkipRows + totalFullRows;

    const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
    const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
    if (!rowStride.isValid()) {
        MOZ_CRASH("Should be checked earlier.");
    }
    const auto tailOffsetBytes = tailOffsetRows * rowStride;

    uploadPtr += tailOffsetBytes.value();

    //////

    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);   // No stride padding.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);  // No padding in general.
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, 0); // Don't skip images,
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, 0);   // or rows.
                                                      // Keep skipping pixels though!

    *out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset,
                                 yOffset+mHeight-1, zOffset+mDepth-1, mWidth, 1, 1,
                                 uploadPtr);

    // Reset all our modified state.
    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, webgl->mPixelStore_UnpackAlignment);
    gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, webgl->mPixelStore_UnpackImageHeight);
    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, webgl->mPixelStore_UnpackRowLength);
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, webgl->mPixelStore_UnpackSkipImages);
    gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, webgl->mPixelStore_UnpackSkipRows);

    return true;
}
Ejemplo n.º 4
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
}
Ejemplo n.º 5
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.
}
Ejemplo n.º 6
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
}