Example #1
0
void
WebGLTexture::Bind(TexTarget aTexTarget) {
    // this function should only be called by bindTexture().
    // it assumes that the GL context is already current.

    bool firstTimeThisTextureIsBound = !HasEverBeenBound();

    if (firstTimeThisTextureIsBound) {
        BindTo(aTexTarget);
    } else if (aTexTarget != Target()) {
        mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
        // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
        // very strange 'invalid write' crashes.
        return;
    }

    GLuint name = GLName();

    mContext->gl->fBindTexture(aTexTarget.get(), name);

    if (firstTimeThisTextureIsBound) {
        mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? 6 : 1;
        EnsureMaxLevelWithCustomImagesAtLeast(0);
        SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);

        // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
        // present in GLES 2, but is present in GL and it seems as if for cube maps
        // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
        if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
            mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
    }
}
Example #2
0
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, TexTarget target, GLenum format)
    : mGL(gl)
    , mGLName(0)
{
  MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);

  mGL->MakeCurrent();
  GLuint formerBinding = 0;
  gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
                   ? LOCAL_GL_TEXTURE_BINDING_2D
                   : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
                   &formerBinding);
  gl->fGenTextures(1, &mGLName);
  gl->fBindTexture(target.get(), mGLName);

  // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
  // to minimize the risk of running into a driver bug in texImage2D, as it is
  // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
  // that texImage2D expects.
  UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1, 16));
  if (target == LOCAL_GL_TEXTURE_2D) {
      gl->fTexImage2D(target.get(), 0, format, 1, 1,
                      0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
  } else {
      for (GLuint i = 0; i < 6; ++i) {
          gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
                          0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
      }
  }

  gl->fBindTexture(target.get(), formerBinding);
}
JS::Value
WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
{
    switch (pname) {
        case LOCAL_GL_TEXTURE_BASE_LEVEL:
        case LOCAL_GL_TEXTURE_COMPARE_FUNC:
        case LOCAL_GL_TEXTURE_COMPARE_MODE:
        case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
        case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
        case LOCAL_GL_TEXTURE_MAX_LEVEL:
        case LOCAL_GL_TEXTURE_SWIZZLE_A:
        case LOCAL_GL_TEXTURE_SWIZZLE_B:
        case LOCAL_GL_TEXTURE_SWIZZLE_G:
        case LOCAL_GL_TEXTURE_SWIZZLE_R:
        case LOCAL_GL_TEXTURE_WRAP_R:
        {
            GLint i = 0;
            gl->fGetTexParameteriv(target.get(), pname, &i);
            return JS::NumberValue(uint32_t(i));
        }

        case LOCAL_GL_TEXTURE_MAX_LOD:
        case LOCAL_GL_TEXTURE_MIN_LOD:
        {
            GLfloat f = 0.0f;
            gl->fGetTexParameterfv(target.get(), pname, &f);
            return JS::NumberValue(float(f));
        }
    }

    return WebGLContext::GetTexParameterInternal(target, pname);
}
Example #4
0
JS::Value
WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
{
    mContext->MakeContextCurrent();

    GLint i = 0;
    GLfloat f = 0.0f;

    switch (pname) {
    case LOCAL_GL_TEXTURE_MIN_FILTER:
        return JS::NumberValue(uint32_t(mMinFilter.get()));

    case LOCAL_GL_TEXTURE_MAG_FILTER:
        return JS::NumberValue(uint32_t(mMagFilter.get()));

    case LOCAL_GL_TEXTURE_WRAP_S:
        return JS::NumberValue(uint32_t(mWrapS.get()));

    case LOCAL_GL_TEXTURE_WRAP_T:
        return JS::NumberValue(uint32_t(mWrapT.get()));

    case LOCAL_GL_TEXTURE_BASE_LEVEL:
        return JS::NumberValue(mBaseMipmapLevel);

    case LOCAL_GL_TEXTURE_COMPARE_MODE:
        return JS::NumberValue(uint32_t(mTexCompareMode));

    case LOCAL_GL_TEXTURE_MAX_LEVEL:
        return JS::NumberValue(mMaxMipmapLevel);

    case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
        return JS::BooleanValue(mImmutable);

    case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
        return JS::NumberValue(uint32_t(mImmutableLevelCount));

    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    case LOCAL_GL_TEXTURE_WRAP_R:
        mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
        return JS::NumberValue(uint32_t(i));

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    case LOCAL_GL_TEXTURE_MAX_LOD:
    case LOCAL_GL_TEXTURE_MIN_LOD:
        mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
        return JS::NumberValue(float(f));

    default:
        MOZ_CRASH("GFX: Unhandled pname.");
    }
}
Example #5
0
void
WebGLTexture::GenerateMipmap(TexTarget texTarget)
{
    const TexImageTarget imageTarget = (texTarget == LOCAL_GL_TEXTURE_2D)
                                                  ? LOCAL_GL_TEXTURE_2D
                                                  : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
    if (!IsMipmapRangeValid())
    {
        return mContext->ErrorInvalidOperation("generateMipmap: Texture does not have a valid mipmap range.");
    }
    if (!HasImageInfoAt(imageTarget, EffectiveBaseMipmapLevel()))
    {
        return mContext->ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
    }

    if (!mContext->IsWebGL2() && !IsFirstImagePowerOfTwo())
        return mContext->ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");

    TexInternalFormat internalformat = ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
    if (IsTextureFormatCompressed(internalformat))
        return mContext->ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");

    if (mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
        (IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
    {
        return mContext->ErrorInvalidOperation("generateMipmap: "
                                     "A texture that has a base internal format of "
                                     "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
    }

    if (!AreAllLevel0ImageInfosEqual())
        return mContext->ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");

    SetGeneratedMipmap();

    mContext->MakeContextCurrent();
    gl::GLContext* gl = mContext->gl;

    if (gl->WorkAroundDriverBugs()) {
        // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
        // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
        // overhead so we do it unconditionally.
        //
        // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
        gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
        gl->fGenerateMipmap(texTarget.get());
        gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, MinFilter().get());
    } else {
        gl->fGenerateMipmap(texTarget.get());
    }
}
Example #6
0
bool
WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack)
{
    MOZ_ASSERT(fakeBlack == FakeBlackType::RGBA0000 ||
               fakeBlack == FakeBlackType::RGBA0001);

    const auto fnGetSlot = [this, target, fakeBlack]() -> UniquePtr<FakeBlackTexture>*
    {
        switch (fakeBlack) {
        case FakeBlackType::RGBA0000:
            switch (target.get()) {
            case LOCAL_GL_TEXTURE_2D      : return &mFakeBlack_2D_0000;
            case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0000;
            case LOCAL_GL_TEXTURE_3D      : return &mFakeBlack_3D_0000;
            case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0000;
            default: return nullptr;
            }

        case FakeBlackType::RGBA0001:
            switch (target.get()) {
            case LOCAL_GL_TEXTURE_2D      : return &mFakeBlack_2D_0001;
            case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0001;
            case LOCAL_GL_TEXTURE_3D      : return &mFakeBlack_3D_0001;
            case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0001;
            default: return nullptr;
            }

        default:
            return nullptr;
        }
    };

    UniquePtr<FakeBlackTexture>* slot = fnGetSlot();
    if (!slot) {
        MOZ_CRASH("GFX: fnGetSlot failed.");
    }
    UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;

    if (!fakeBlackTex) {
        fakeBlackTex = FakeBlackTexture::Create(gl, target, fakeBlack);
        if (!fakeBlackTex) {
            return false;
        }
    }

    gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
    gl->fBindTexture(target.get(), fakeBlackTex->mGLName);
    gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
    return true;
}
Example #7
0
static void SetSwizzle(gl::GLContext* gl, TexTarget target,
                       const GLint* swizzle) {
  static const GLint kNoSwizzle[4] = {LOCAL_GL_RED, LOCAL_GL_GREEN,
                                      LOCAL_GL_BLUE, LOCAL_GL_ALPHA};
  if (!swizzle) {
    swizzle = kNoSwizzle;
  } else if (!gl->IsSupported(gl::GLFeature::texture_swizzle)) {
    MOZ_CRASH("GFX: Needs swizzle feature to swizzle!");
  }

  gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_SWIZZLE_R, swizzle[0]);
  gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_SWIZZLE_G, swizzle[1]);
  gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_SWIZZLE_B, swizzle[2]);
  gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_SWIZZLE_A, swizzle[3]);
}
WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target,
                                                 FakeBlackType type)
    : mGL(gl)
    , mGLName(CreateGLTexture(gl))
{
    GLenum texFormat;
    switch (type) {
    case FakeBlackType::RGBA0000:
        texFormat = LOCAL_GL_RGBA;
        break;

    case FakeBlackType::RGBA0001:
        texFormat = LOCAL_GL_RGB;
        break;

    default:
        MOZ_CRASH("bad type");
    }

    gl::ScopedBindTexture scopedBind(mGL, mGLName, target.get());

    mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
    mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);

    // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
    // minimize the risk of running into a driver bug in texImage2D, as it is a bit
    // unusual maybe to create 1x1 textures, and the stack may not have the alignment that
    // TexImage2D expects.

    const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
    UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.

    if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
        for (int i = 0; i < 6; ++i) {
            const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
            const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1,
                                            zeros.get());
            if (error)
                MOZ_CRASH("Unexpected error during FakeBlack creation.");
        }
    } else {
        const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1,
                                        zeros.get());
        if (error)
            MOZ_CRASH("Unexpected error during FakeBlack creation.");
    }
}
Example #9
0
JS::Value
WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
{
    mContext->MakeContextCurrent();

    GLint i = 0;
    GLfloat f = 0.0f;

    switch (pname) {
    case LOCAL_GL_TEXTURE_MIN_FILTER:
    case LOCAL_GL_TEXTURE_MAG_FILTER:
    case LOCAL_GL_TEXTURE_WRAP_S:
    case LOCAL_GL_TEXTURE_WRAP_T:
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    case LOCAL_GL_TEXTURE_COMPARE_MODE:
    case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
    case LOCAL_GL_TEXTURE_SWIZZLE_A:
    case LOCAL_GL_TEXTURE_SWIZZLE_B:
    case LOCAL_GL_TEXTURE_SWIZZLE_G:
    case LOCAL_GL_TEXTURE_SWIZZLE_R:
    case LOCAL_GL_TEXTURE_WRAP_R:
        mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
        return JS::NumberValue(uint32_t(i));

    case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
        mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
        return JS::BooleanValue(bool(i));

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    case LOCAL_GL_TEXTURE_MAX_LOD:
    case LOCAL_GL_TEXTURE_MIN_LOD:
        mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
        return JS::NumberValue(float(f));

    default:
        MOZ_CRASH("GFX: Unhandled pname.");
    }
}
JS::Value
WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
{
    switch (pname) {
        case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
        case LOCAL_GL_TEXTURE_BASE_LEVEL:
        case LOCAL_GL_TEXTURE_MAX_LEVEL:
        {
            GLint i = 0;
            gl->fGetTexParameteriv(target.get(), pname, &i);
            return JS::NumberValue(uint32_t(i));
        }
    }
    return WebGLContext::GetTexParameterInternal(target, pname);
}
Example #11
0
bool
WebGLTexture::BindTexture(TexTarget texTarget)
{
    if (IsDeleted()) {
        mContext->ErrorInvalidOperation("bindTexture: Cannot bind a deleted object.");
        return false;
    }

    const bool isFirstBinding = !HasEverBeenBound();
    if (!isFirstBinding && mTarget != texTarget) {
        mContext->ErrorInvalidOperation("bindTexture: This texture has already been bound"
                                        " to a different target.");
        return false;
    }

    mTarget = texTarget;

    mContext->gl->fBindTexture(mTarget.get(), mGLName);

    if (isFirstBinding) {
        mFaceCount = IsCubeMap() ? 6 : 1;

        gl::GLContext* gl = mContext->gl;

        // Thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R
        // is not present in GLES 2, but is present in GL and it seems as if for
        // cube maps we need to set it to GL_CLAMP_TO_EDGE to get the expected
        // GLES behavior.
        // If we are WebGL 2 though, we'll want to leave it as REPEAT.
        const bool hasWrapR = gl->IsSupported(gl::GLFeature::texture_3D);
        if (IsCubeMap() && hasWrapR && !mContext->IsWebGL2()) {
            gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_WRAP_R,
                               LOCAL_GL_CLAMP_TO_EDGE);
        }
    }

    return true;
}
Example #12
0
// Here we have to support all pnames with both int and float params.
// See this discussion:
//   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
void
WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, GLint* maybeIntParam,
                           GLfloat* maybeFloatParam)
{
    MOZ_ASSERT(maybeIntParam || maybeFloatParam);

    GLint   intParam   = maybeIntParam   ? *maybeIntParam   : GLint(*maybeFloatParam);
    GLfloat floatParam = maybeFloatParam ? *maybeFloatParam : GLfloat(*maybeIntParam);

    bool isPNameValid = false;
    switch (pname) {
    // GLES 2.0.25 p76:
    case LOCAL_GL_TEXTURE_WRAP_S:
    case LOCAL_GL_TEXTURE_WRAP_T:
    case LOCAL_GL_TEXTURE_MIN_FILTER:
    case LOCAL_GL_TEXTURE_MAG_FILTER:
        isPNameValid = true;
        break;

    // GLES 3.0.4 p149-150:
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_COMPARE_MODE:
    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
    case LOCAL_GL_TEXTURE_MAX_LOD:
    case LOCAL_GL_TEXTURE_MIN_LOD:
    case LOCAL_GL_TEXTURE_WRAP_R:
        if (mContext->IsWebGL2())
            isPNameValid = true;
        break;

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
        if (mContext->IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic))
            isPNameValid = true;
        break;
    }

    if (!isPNameValid) {
        mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
        return;
    }

    ////////////////
    // Validate params and invalidate if needed.

    bool paramBadEnum = false;
    bool paramBadValue = false;

    switch (pname) {
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
        paramBadValue = (intParam < 0);
        break;

    case LOCAL_GL_TEXTURE_COMPARE_MODE:
        paramBadValue = (intParam != LOCAL_GL_NONE &&
                         intParam != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
        break;

    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
        switch (intParam) {
        case LOCAL_GL_LEQUAL:
        case LOCAL_GL_GEQUAL:
        case LOCAL_GL_LESS:
        case LOCAL_GL_GREATER:
        case LOCAL_GL_EQUAL:
        case LOCAL_GL_NOTEQUAL:
        case LOCAL_GL_ALWAYS:
        case LOCAL_GL_NEVER:
            break;

        default:
            paramBadValue = true;
            break;
        }
        break;

    case LOCAL_GL_TEXTURE_MIN_FILTER:
        switch (intParam) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
            break;

        default:
            paramBadEnum = true;
            break;
        }
        break;

    case LOCAL_GL_TEXTURE_MAG_FILTER:
        switch (intParam) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
            break;

        default:
            paramBadEnum = true;
            break;
        }
        break;

    case LOCAL_GL_TEXTURE_WRAP_S:
    case LOCAL_GL_TEXTURE_WRAP_T:
    case LOCAL_GL_TEXTURE_WRAP_R:
        switch (intParam) {
        case LOCAL_GL_CLAMP_TO_EDGE:
        case LOCAL_GL_MIRRORED_REPEAT:
        case LOCAL_GL_REPEAT:
            break;

        default:
            paramBadEnum = true;
            break;
        }
        break;

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
        if (maybeFloatParam && floatParam < 1.0f)
            paramBadValue = true;
        else if (maybeIntParam && intParam < 1)
            paramBadValue = true;

        break;
    }

    if (paramBadEnum) {
        if (maybeIntParam) {
            mContext->ErrorInvalidEnum("texParameteri: pname 0x%04x: Invalid param"
                                       " 0x%04x.",
                                       pname, intParam);
        } else {
            mContext->ErrorInvalidEnum("texParameterf: pname 0x%04x: Invalid param %g.",
                                       pname, floatParam);
        }
        return;
    }

    if (paramBadValue) {
        if (maybeIntParam) {
            mContext->ErrorInvalidValue("texParameteri: pname 0x%04x: Invalid param %i"
                                        " (0x%x).",
                                        pname, intParam, intParam);
        } else {
            mContext->ErrorInvalidValue("texParameterf: pname 0x%04x: Invalid param %g.",
                                        pname, floatParam);
        }
        return;
    }

    ////////////////
    // Store any needed values

    switch (pname) {
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
        mBaseMipmapLevel = intParam;
        ClampLevelBaseAndMax();
        break;

    case LOCAL_GL_TEXTURE_MAX_LEVEL:
        mMaxMipmapLevel = intParam;
        ClampLevelBaseAndMax();
        break;

    case LOCAL_GL_TEXTURE_MIN_FILTER:
        mMinFilter = intParam;
        break;

    case LOCAL_GL_TEXTURE_MAG_FILTER:
        mMagFilter = intParam;
        break;

    case LOCAL_GL_TEXTURE_WRAP_S:
        mWrapS = intParam;
        break;

    case LOCAL_GL_TEXTURE_WRAP_T:
        mWrapT = intParam;
        break;

    // We don't actually need to store the WRAP_R, since it doesn't change texture
    // completeness rules.
    }

    // Only a couple of pnames don't need to invalidate our resolve status cache.
    switch (pname) {
    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
    case LOCAL_GL_TEXTURE_WRAP_R:
        break;

    default:
        InvalidateResolveCache();
        break;
    }

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

    mContext->MakeContextCurrent();
    if (maybeIntParam)
        mContext->gl->fTexParameteri(texTarget.get(), pname, intParam);
    else
        mContext->gl->fTexParameterf(texTarget.get(), pname, floatParam);
}
Example #13
0
void
WebGLTexture::GenerateMipmap(TexTarget texTarget)
{
    // GLES 3.0.4 p160:
    // "Mipmap generation replaces texel array levels level base + 1 through q with arrays
    //  derived from the level base array, regardless of their previous contents. All
    //  other mipmap arrays, including the level base array, are left unchanged by this
    //  computation."
    const ImageInfo& baseImageInfo = BaseImageInfo();
    if (!baseImageInfo.IsDefined()) {
        mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture is"
                                        " not defined.");
        return;
    }

    if (IsCubeMap() && !IsCubeComplete()) {
      mContext->ErrorInvalidOperation("generateMipmap: Cube maps must be \"cube"
                                      " complete\".");
      return;
    }

    if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
        mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture"
                                        " does not have power-of-two dimensions.");
        return;
    }

    auto format = baseImageInfo.mFormat->format;
    if (format->compression) {
        mContext->ErrorInvalidOperation("generateMipmap: Texture data at base level is"
                                        " compressed.");
        return;
    }

    if (format->hasDepth) {
        mContext->ErrorInvalidOperation("generateMipmap: Depth textures are not"
                                        " supported.");
        return;
    }

    // OpenGL ES 3.0.4 p160:
    // If the level base array was not specified with an unsized internal format from
    // table 3.3 or a sized internal format that is both color-renderable and
    // texture-filterable according to table 3.13, an INVALID_OPERATION error
    // is generated.
    const auto usage = baseImageInfo.mFormat;
    bool canGenerateMipmap = (usage->isRenderable && usage->isFilterable);
    switch (usage->format->effectiveFormat) {
    case webgl::EffectiveFormat::Luminance8:
    case webgl::EffectiveFormat::Alpha8:
    case webgl::EffectiveFormat::Luminance8Alpha8:
        // Non-color-renderable formats from Table 3.3.
        canGenerateMipmap = true;
        break;
    default:
        break;
    }

    if (!canGenerateMipmap) {
        mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not unsized"
                                        " internal format or is not"
                                        " color-renderable or texture-filterable.");
        return;
    }

    // Done with validation. Do the operation.

    mContext->MakeContextCurrent();
    gl::GLContext* gl = mContext->gl;

    if (gl->WorkAroundDriverBugs()) {
        // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
        // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
        // overhead so we do it unconditionally.
        //
        // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
        gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
                           LOCAL_GL_NEAREST_MIPMAP_NEAREST);
        gl->fGenerateMipmap(texTarget.get());
        gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER,
                           mMinFilter.get());
    } else {
        gl->fGenerateMipmap(texTarget.get());
    }

    // Record the results.
    // Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
    // mBaseMipmapLevel if the min filter doesn't require mipmaps.
    const uint32_t lastLevel = mBaseMipmapLevel + baseImageInfo.MaxMipmapLevels() - 1;
    PopulateMipChain(mBaseMipmapLevel, lastLevel);
}
Example #14
0
// Here we have to support all pnames with both int and float params.
// See this discussion:
//   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
void
WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, GLint* maybeIntParam,
                           GLfloat* maybeFloatParam)
{
    MOZ_ASSERT(maybeIntParam || maybeFloatParam);

    GLint   intParam   = maybeIntParam   ? *maybeIntParam   : GLint(*maybeFloatParam);
    GLfloat floatParam = maybeFloatParam ? *maybeFloatParam : GLfloat(*maybeIntParam);

    bool paramBadEnum = false;
    bool paramBadValue = false;

    switch (pname) {
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
        if (!mContext->IsWebGL2())
            return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);

        if (intParam < 0) {
            paramBadValue = true;
            break;
        }

        SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);

        if (pname == LOCAL_GL_TEXTURE_BASE_LEVEL)
            mBaseMipmapLevel = intParam;
        else
            mMaxMipmapLevel = intParam;

        break;

    case LOCAL_GL_TEXTURE_COMPARE_MODE:
        if (!mContext->IsWebGL2())
            return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);

        paramBadValue = (intParam != LOCAL_GL_NONE &&
                         intParam != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
        break;

    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
        if (!mContext->IsWebGL2())
            return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);

        switch (intParam) {
        case LOCAL_GL_LEQUAL:
        case LOCAL_GL_GEQUAL:
        case LOCAL_GL_LESS:
        case LOCAL_GL_GREATER:
        case LOCAL_GL_EQUAL:
        case LOCAL_GL_NOTEQUAL:
        case LOCAL_GL_ALWAYS:
        case LOCAL_GL_NEVER:
            break;

        default:
            paramBadValue = true;
        }
        break;

    case LOCAL_GL_TEXTURE_MIN_FILTER:
        switch (intParam) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
            SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
            mMinFilter = intParam;
            break;

        default:
            paramBadEnum = true;
        }
        break;

    case LOCAL_GL_TEXTURE_MAG_FILTER:
        switch (intParam) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
            SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
            mMagFilter = intParam;
            break;

        default:
            paramBadEnum = true;
        }
        break;

    case LOCAL_GL_TEXTURE_WRAP_S:
        switch (intParam) {
        case LOCAL_GL_CLAMP_TO_EDGE:
        case LOCAL_GL_MIRRORED_REPEAT:
        case LOCAL_GL_REPEAT:
            SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
            mWrapS = intParam;
            break;

        default:
            paramBadEnum = true;
        }
        break;

    case LOCAL_GL_TEXTURE_WRAP_T:
        switch (intParam) {
        case LOCAL_GL_CLAMP_TO_EDGE:
        case LOCAL_GL_MIRRORED_REPEAT:
        case LOCAL_GL_REPEAT:
            SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
            mWrapT = intParam;
            break;

        default:
            paramBadEnum = true;
        }
        break;

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
        if (!mContext->IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic))
            return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);

        if (maybeFloatParam && floatParam < 1.0f)
            paramBadValue = true;
        else if (maybeIntParam && intParam < 1)
            paramBadValue = true;

        break;

    default:
        return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
    }

    if (paramBadEnum) {
        if (maybeIntParam) {
            mContext->ErrorInvalidEnum("texParameteri: pname 0x%04x: Invalid param"
                                       " 0x%04x.",
                                       pname, intParam);
        } else {
            mContext->ErrorInvalidEnum("texParameterf: pname 0x%04x: Invalid param %g.",
                                       pname, floatParam);
        }
        return;
    }

    if (paramBadValue) {
        if (maybeIntParam) {
            mContext->ErrorInvalidValue("texParameteri: pname 0x%04x: Invalid param %i"
                                        " (0x%x).",
                                        pname, intParam, intParam);
        } else {
            mContext->ErrorInvalidValue("texParameterf: pname 0x%04x: Invalid param %g.",
                                        pname, floatParam);
        }
        return;
    }

    mContext->MakeContextCurrent();
    if (maybeIntParam)
        mContext->gl->fTexParameteri(texTarget.get(), pname, intParam);
    else
        mContext->gl->fTexParameterf(texTarget.get(), pname, floatParam);
}
Example #15
0
// Here we have to support all pnames with both int and float params.
// See this discussion:
//   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
void WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname,
                                const FloatOrInt& param) {
  bool isPNameValid = false;
  switch (pname) {
    // GLES 2.0.25 p76:
    case LOCAL_GL_TEXTURE_WRAP_S:
    case LOCAL_GL_TEXTURE_WRAP_T:
    case LOCAL_GL_TEXTURE_MIN_FILTER:
    case LOCAL_GL_TEXTURE_MAG_FILTER:
      isPNameValid = true;
      break;

    // GLES 3.0.4 p149-150:
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_COMPARE_MODE:
    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
    case LOCAL_GL_TEXTURE_MAX_LOD:
    case LOCAL_GL_TEXTURE_MIN_LOD:
    case LOCAL_GL_TEXTURE_WRAP_R:
      if (mContext->IsWebGL2()) isPNameValid = true;
      break;

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
      if (mContext->IsExtensionEnabled(
              WebGLExtensionID::EXT_texture_filter_anisotropic))
        isPNameValid = true;
      break;
  }

  if (!isPNameValid) {
    mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
    return;
  }

  ////////////////
  // Validate params and invalidate if needed.

  bool paramBadEnum = false;
  bool paramBadValue = false;

  switch (pname) {
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
    case LOCAL_GL_TEXTURE_MAX_LEVEL:
      paramBadValue = (param.i < 0);
      break;

    case LOCAL_GL_TEXTURE_COMPARE_MODE:
      paramBadValue = (param.i != LOCAL_GL_NONE &&
                       param.i != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
      break;

    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
      switch (param.i) {
        case LOCAL_GL_LEQUAL:
        case LOCAL_GL_GEQUAL:
        case LOCAL_GL_LESS:
        case LOCAL_GL_GREATER:
        case LOCAL_GL_EQUAL:
        case LOCAL_GL_NOTEQUAL:
        case LOCAL_GL_ALWAYS:
        case LOCAL_GL_NEVER:
          break;

        default:
          paramBadValue = true;
          break;
      }
      break;

    case LOCAL_GL_TEXTURE_MIN_FILTER:
      switch (param.i) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
          break;

        default:
          paramBadEnum = true;
          break;
      }
      break;

    case LOCAL_GL_TEXTURE_MAG_FILTER:
      switch (param.i) {
        case LOCAL_GL_NEAREST:
        case LOCAL_GL_LINEAR:
          break;

        default:
          paramBadEnum = true;
          break;
      }
      break;

    case LOCAL_GL_TEXTURE_WRAP_S:
    case LOCAL_GL_TEXTURE_WRAP_T:
    case LOCAL_GL_TEXTURE_WRAP_R:
      switch (param.i) {
        case LOCAL_GL_CLAMP_TO_EDGE:
        case LOCAL_GL_MIRRORED_REPEAT:
        case LOCAL_GL_REPEAT:
          break;

        default:
          paramBadEnum = true;
          break;
      }
      break;

    case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
      if (param.f < 1.0f) paramBadValue = true;

      break;
  }

  if (paramBadEnum) {
    if (!param.isFloat) {
      mContext->ErrorInvalidEnum(
          "pname 0x%04x: Invalid param"
          " 0x%04x.",
          pname, param.i);
    } else {
      mContext->ErrorInvalidEnum("pname 0x%04x: Invalid param %g.", pname,
                                 param.f);
    }
    return;
  }

  if (paramBadValue) {
    if (!param.isFloat) {
      mContext->ErrorInvalidValue(
          "pname 0x%04x: Invalid param %i"
          " (0x%x).",
          pname, param.i, param.i);
    } else {
      mContext->ErrorInvalidValue("pname 0x%04x: Invalid param %g.", pname,
                                  param.f);
    }
    return;
  }

  ////////////////
  // Store any needed values

  FloatOrInt clamped = param;
  bool invalidate = true;
  switch (pname) {
    case LOCAL_GL_TEXTURE_BASE_LEVEL:
      mBaseMipmapLevel = clamped.i;
      ClampLevelBaseAndMax();
      clamped = FloatOrInt(GLint(mBaseMipmapLevel));
      break;

    case LOCAL_GL_TEXTURE_MAX_LEVEL:
      mMaxMipmapLevel = clamped.i;
      ClampLevelBaseAndMax();
      clamped = FloatOrInt(GLint(mMaxMipmapLevel));
      break;

    case LOCAL_GL_TEXTURE_MIN_FILTER:
      mSamplingState.minFilter = clamped.i;
      break;

    case LOCAL_GL_TEXTURE_MAG_FILTER:
      mSamplingState.magFilter = clamped.i;
      break;

    case LOCAL_GL_TEXTURE_WRAP_S:
      mSamplingState.wrapS = clamped.i;
      break;

    case LOCAL_GL_TEXTURE_WRAP_T:
      mSamplingState.wrapT = clamped.i;
      break;

    case LOCAL_GL_TEXTURE_COMPARE_MODE:
      mSamplingState.compareMode = clamped.i;
      break;

    default:
      invalidate = false;  // Texture completeness will not change.
      break;
  }

  if (invalidate) {
    InvalidateCaches();
  }

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

  if (!clamped.isFloat)
    mContext->gl->fTexParameteri(texTarget.get(), pname, clamped.i);
  else
    mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f);
}