| 105 | const int MaxCopyPerFrame = 32768; |
| 106 | |
| 107 | MipInfo TextBankGL33::UseMipmap(Texture* absTexture, int level, int top) |
| 108 | { |
| 109 | if (!absTexture) |
| 110 | return MipInfo(nullptr, 0); |
| 111 | |
| 112 | TextureGL33* texture = static_cast<TextureGL33*>(absTexture); |
| 113 | texture->LoadHeadersNV(); |
| 114 | |
| 115 | // Dynamic textures (CreateDynamic — font atlases, etc.) have no _src to |
| 116 | // demand-load from. Their content is already in _surface from |
| 117 | // InitFromRGBA, and any updates go through UpdateRGBA. Routing them |
| 118 | // through the LoadSmall / LoadLevels paths below allocates an empty |
| 119 | // _smallSurface, hands its handle to ApplyPassState, and the resulting |
| 120 | // sample reads garbage / zero alpha — the FPS overlay and FreeType atlas |
| 121 | // pages never paint. Short-circuit to the existing _surface. |
| 122 | if (!texture->_src && texture->_surface.GetTexture()) |
| 123 | return MipInfo(texture, 0); |
| 124 | |
| 125 | saturateMin(level, texture->_mipmapNeeded); |
| 126 | saturateMin(top, texture->_mipmapWanted); |
| 127 | |
| 128 | if (level < 0) |
| 129 | level = 0; |
| 130 | |
| 131 | saturateMin(level, texture->_nMipmaps - 1); |
| 132 | saturateMax(top, texture->_largestUsed); |
| 133 | saturateMin(top, level); |
| 134 | saturateMax(level, top); |
| 135 | |
| 136 | // Never use mipmaps smaller than some limit |
| 137 | int limitUse = _maxSmallTexturePixels / 4; |
| 138 | for (; level > 0; level--) |
| 139 | { |
| 140 | PacLevelMem* mipTop = &texture->_mipmaps[level]; |
| 141 | if (mipTop->_w * mipTop->_h >= limitUse) |
| 142 | break; |
| 143 | } |
| 144 | |
| 145 | saturateMin(top, level); |
| 146 | |
| 147 | // Budget gate is lifted while a load boost is active — mission load |
| 148 | // wants every touched texture at its wanted level before the reveal. |
| 149 | if (_loadBoostFrames <= 0 && (_thisFrameCopied > MaxCopyPerFrame || _thisFrameAlloc > MaxAllocationsPerFrame)) |
| 150 | { |
| 151 | if (texture->_levelLoaded < texture->_nMipmaps) |
| 152 | { |
| 153 | top = level = texture->_levelLoaded; |
| 154 | } |
| 155 | else if (texture->_smallLoaded < texture->_nMipmaps) |
| 156 | { |
| 157 | top = level = texture->_smallLoaded; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | // Use small texture if adequate |
| 162 | if (texture->_smallLoaded <= level) |
| 163 | { |
| 164 | if (texture->LoadSmall() < 0) |
no test coverage detected