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); }
void WebGLTexture::GenerateMipmap() { // GLES 3.0.4 p160: // "Mipmap generation replaces texel array levels level base + 1 through q // with arrrays 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." // But only check and init the base level. const bool ensureInit = true; const bool skipMips = true; const auto completeness = CalcCompletenessInfo(ensureInit, skipMips); if (!completeness || !completeness->levels) { mContext->ErrorInvalidOperation( "The texture's base level must be complete."); return; } const auto& usage = completeness->usage; const auto& format = usage->format; if (!mContext->IsWebGL2()) { if (!completeness->powerOfTwo) { mContext->ErrorInvalidOperation( "The base level of the texture does not" " have power-of-two dimensions."); return; } if (format->isSRGB) { mContext->ErrorInvalidOperation( "EXT_sRGB forbids GenerateMipmap with" " sRGB."); return; } } if (format->compression) { mContext->ErrorInvalidOperation( "Texture data at base level is compressed."); return; } if (format->d) { mContext->ErrorInvalidOperation("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. 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( "Texture at base level is not unsized" " internal format or is not" " color-renderable or texture-filterable."); return; } // Done with validation. Do the operation. 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(mTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST); gl->fGenerateMipmap(mTarget.get()); gl->fTexParameteri(mTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, mSamplingState.minFilter.get()); } else { gl->fGenerateMipmap(mTarget.get()); } // Record the results. const auto maxLevel = EffectiveMaxLevel(); PopulateMipChain(maxLevel); }