#1870 Tune up for better experience on integrated intel with low memory (#1872)

* More deterministic vsize calculation.   Add control for choosing downscale method.
* Quick hack to make GLTF preview work again
master
Dave Parks 2024-07-03 17:42:24 -05:00 committed by GitHub
parent 9a38ecee8e
commit 08b933a0c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 409 additions and 170 deletions

View File

@ -79,6 +79,7 @@ LLFileSystem::~LLFileSystem()
// static
bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType file_type)
{
LL_PROFILE_ZONE_SCOPED;
std::string id_str;
file_id.toString(id_str);
const std::string extra_info = "";

View File

@ -484,6 +484,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
void *user_data,
bool is_priority)
{
LL_PROFILE_ZONE_SCOPED;
LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL;
LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL;
@ -529,6 +531,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
if (size > 0)
{
LL_PROFILE_ZONE_NAMED("gad - file in cache");
// we've already got the file
// theoretically, partial files w/o a pending request shouldn't happen
// unless there's a weird error
@ -548,7 +551,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
}
bool duplicate = false;
LL_PROFILE_ZONE_NAMED("gad - check pending downloads");
// check to see if there's a pending download of this uuid already
for (request_list_t::iterator iter = mPendingDownloads.begin();
iter != mPendingDownloads.end(); ++iter )

View File

@ -102,6 +102,9 @@ public:
bool mIsNVIDIA;
bool mIsIntel;
// hints to the render pipe
U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod
#if LL_DARWIN
// Needed to distinguish problem cards on older Macs that break with Materials
bool mIsMobileGF;

View File

@ -57,6 +57,9 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;
U32 wpo2(U32 i);
U32 LLImageGL::sFrameCount = 0;
// texture memory accounting (for macOS)
static LLMutex sTexMemMutex;
static std::unordered_map<U32, U64> sTextureAllocs;
@ -1003,7 +1006,7 @@ bool should_stagger_image_set(bool compressed)
#else
// glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08
// Setting media textures off-thread seems faster when not using sub_image_lines (Nvidia/Windows 10) -Cosmic,2023-03-31
return !compressed && on_main_thread();
return !compressed && on_main_thread() && !gGLManager.mIsIntel;
#endif
}
@ -1185,13 +1188,37 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
}
// static
void LLImageGL::updateClass()
{
sFrameCount++;
}
// static
void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
{
// wait a few frames before actually deleting the textures to avoid
// synchronization issues with the GPU
static std::vector<U32> sFreeList[4];
if (gGLManager.mInited)
{
free_tex_images(numTextures, textures);
glDeleteTextures(numTextures, textures);
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 idx = sFrameCount % 4;
for (S32 i = 0; i < numTextures; ++i)
{
sFreeList[idx].push_back(textures[i]);
}
idx = (sFrameCount + 3) % 4;
if (!sFreeList[idx].empty())
{
glDeleteTextures((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
}
@ -2335,45 +2362,86 @@ bool LLImageGL::scaleDown(S32 desired_discard)
S32 desired_width = getWidth(desired_discard);
S32 desired_height = getHeight(desired_discard);
U64 size = getBytes(desired_discard);
llassert(size <= 2048*2048*4); // we shouldn't be using this method to downscale huge textures, but it'll work
gGL.getTexUnit(0)->bind(this);
if (gGLManager.mDownScaleMethod == 0)
{ // use an FBO to downscale the texture
// allocate new texture
U32 temp_texname = 0;
generateTextures(1, &temp_texname);
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, temp_texname, true);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glTexImage2D");
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
}
// account for new texture getting created
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
if (sScratchPBO == 0)
{
glGenBuffers(1, &sScratchPBO);
sScratchPBOSize = 0;
// Use render-to-texture to scale down the texture
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glFramebufferTexture2D");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTarget, temp_texname, 0);
}
glViewport(0, 0, desired_width, desired_height);
// draw a full screen triangle
gGL.getTexUnit(0)->bind(this);
glDrawArrays(GL_TRIANGLES, 0, 3);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// delete old texture and assign new texture name
deleteTextures(1, &mTexName);
mTexName = temp_texname;
if (mHasMipMaps)
{ // generate mipmaps if needed
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
gGL.getTexUnit(0)->bind(this);
glGenerateMipmap(mTarget);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
}
else
{ // use a PBO to downscale the texture
U64 size = getBytes(desired_discard);
llassert(size <= 2048 * 2048 * 4); // we shouldn't be using this method to downscale huge textures, but it'll work
gGL.getTexUnit(0)->bind(this);
glBindBuffer(GL_PIXEL_PACK_BUFFER, sScratchPBO);
if (sScratchPBO == 0)
{
glGenBuffers(1, &sScratchPBO);
sScratchPBOSize = 0;
}
if (size > sScratchPBOSize)
{
glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_COPY);
sScratchPBOSize = size;
glBindBuffer(GL_PIXEL_PACK_BUFFER, sScratchPBO);
if (size > sScratchPBOSize)
{
glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_COPY);
sScratchPBOSize = size;
}
glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr);
free_tex_image(mTexName);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
if (mHasMipMaps)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
glGenerateMipmap(mTarget);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
glGetTexImage(mTarget, mip, mFormatPrimary, mFormatType, nullptr);
free_tex_image(mTexName);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
if (mHasMipMaps)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
glGenerateMipmap(mTarget);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
mCurrentDiscardLevel = desired_discard;
return true;

View File

@ -62,6 +62,9 @@ class LLImageGL : public LLRefCount
friend class LLTexUnit;
public:
// call once per frame
static void updateClass();
// Get an estimate of how many bytes have been allocated in vram for textures.
// Does not include mipmaps.
// NOTE: multiplying this number by two gives a good estimate for total
@ -276,7 +279,7 @@ protected:
public:
static std::unordered_set<LLImageGL*> sImageList;
static S32 sCount;
static U32 sFrameCount;
static F32 sLastFrameTime;
// Global memory statistics

View File

@ -297,7 +297,11 @@ public:
ALTERNATE_DIFFUSE_MAP = 1,
NORMAL_MAP = 1,
SPECULAR_MAP = 2,
NUM_TEXTURE_CHANNELS = 3,
BASECOLOR_MAP = 3,
METALLIC_ROUGHNESS_MAP = 4,
GLTF_NORMAL_MAP = 5,
EMISSIVE_MAP = 6,
NUM_TEXTURE_CHANNELS = 7,
};
enum eVolumeTexIndex : U8

View File

@ -426,14 +426,17 @@ void LLRenderTarget::bindTarget()
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3};
glDrawBuffers(static_cast<GLsizei>(mTex.size()), drawbuffers);
if (mTex.empty())
{ //no color buffer to draw to
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
else
{
glDrawBuffers(static_cast<GLsizei>(mTex.size()), drawbuffers);
glReadBuffer(GL_COLOR_ATTACHMENT0);
}
check_framebuffer_status();
glViewport(0, 0, mResX, mResY);
@ -519,7 +522,8 @@ void LLRenderTarget::flush()
llassert(sCurFBO == mFBO);
llassert(sBoundTarget == this);
if (mGenerateMipMaps == LLTexUnit::TMG_AUTO) {
if (mGenerateMipMaps == LLTexUnit::TMG_AUTO)
{
LL_PROFILE_GPU_ZONE("rt generate mipmaps");
bindTexture(0, 0, LLTexUnit::TFO_TRILINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
@ -540,6 +544,8 @@ void LLRenderTarget::flush()
glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
sCurResX = gGLViewport[2];
sCurResY = gGLViewport[3];
glReadBuffer(GL_BACK);
glDrawBuffer(GL_BACK);
}
}

View File

@ -172,6 +172,8 @@ public:
// *HACK
void swapFBORefs(LLRenderTarget& other);
static LLRenderTarget* sBoundTarget;
protected:
U32 mResX;
U32 mResY;
@ -186,8 +188,6 @@ protected:
U32 mMipLevels;
LLTexUnit::eTextureType mUsage;
static LLRenderTarget* sBoundTarget;
};
#endif

View File

@ -7732,7 +7732,7 @@
<key>Comment</key>
<string>Minimum of available physical memory in MB before textures get scaled down</string>
<key>Persist</key>
<integer>1</integer>
<integer>0</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
@ -7771,6 +7771,17 @@
<key>Value</key>
<integer>2048</integer>
</map>
<key>RenderDownScaleMethod</key>
<map>
<key>Comment</key>
<string>Method to use to downscale images. 0 - FBO, 1 - PBO</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderDebugTextureBind</key>
<map>
<key>Comment</key>

View File

@ -1,4 +1,4 @@
version 60
version 61
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -76,6 +76,7 @@ RenderGLMultiThreadedMedia 1 1
RenderReflectionProbeResolution 1 128
RenderScreenSpaceReflections 1 1
RenderMirrors 1 1
RenderDownScaleMethod 1 1
//
@ -366,6 +367,7 @@ RenderAnisotropic 1 0
RenderFSAASamples 1 0
RenderGLContextCoreProfile 1 0
RenderGLMultiThreadedMedia 1 0
RenderDownScaleMethod 1 0
list AMD
RenderGLMultiThreadedTextures 1 1

View File

@ -36,8 +36,6 @@ namespace LL
{
namespace GLTF
{
constexpr S32 INVALID_INDEX = -1;
class Buffer
{
public:

View File

@ -476,6 +476,7 @@ void Asset::update()
{ // HACK - force texture to be loaded full rez
// TODO: calculate actual vsize
image.mTexture->addTextureStats(2048.f * 2048.f);
image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH);
}
}
}

View File

@ -43,6 +43,8 @@ namespace LL
{
namespace GLTF
{
constexpr S32 INVALID_INDEX = -1;
using Value = boost::json::value;
using mat4 = glm::mat4;

View File

@ -345,6 +345,12 @@ void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id)
llassert(obj->getVolume()->getParams().getSculptID() == gltf_id);
llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF);
if (obj->mGLTFAsset)
{ // object already has a GLTF asset, don't reload it
llassert(std::find(mObjects.begin(), mObjects.end(), obj) != mObjects.end());
return;
}
obj->ref();
gAssetStorage->getAssetData(gltf_id, LLAssetType::AT_GLTF, onGLTFLoadComplete, obj);
}

View File

@ -2210,10 +2210,10 @@ bool LLAppViewer::initThreads()
cores = llmin(cores, (S32) max_cores);
}
// The only configurable thread count right now is ImageDecode
// The viewer typically starts around 8 threads not including image decode,
// so try to leave at least one core free
S32 image_decode_count = llclamp(cores - 9, 1, 8);
// always use at least 2 threads for image decoding to prevent
// a single texture blocking all other textures from decoding
S32 image_decode_count = llclamp(cores - 6, 2, 16);
threadCounts["ImageDecode"] = image_decode_count;
gSavedSettings.setLLSD("ThreadPoolSizes", threadCounts);
@ -4609,6 +4609,10 @@ void LLAppViewer::idle()
LLGLTFMaterialList::flushUpdates();
static LLCachedControl<U32> downscale_method(gSavedSettings, "RenderDownScaleMethod");
gGLManager.mDownScaleMethod = downscale_method;
LLImageGL::updateClass();
// Service the WorkQueue we use for replies from worker threads.
// Use function statics for the timeslice setting so we only have to fetch
// and convert MainWorkTime once.

View File

@ -81,10 +81,6 @@ LLDrawPoolAlpha::~LLDrawPoolAlpha()
void LLDrawPoolAlpha::prerender()
{
mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
// TODO: is this even necessay? These are probably set to never discard
LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f);
LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f);
}
S32 LLDrawPoolAlpha::getNumPostDeferredPasses()

View File

@ -169,6 +169,8 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
mImportanceToCamera = 0.f ;
mBoundingSphereRadius = 0.0f ;
mTexExtents[0].set(0, 0);
mTexExtents[1].set(1, 1);
mHasMedia = false ;
mIsMediaAllowed = true;
}
@ -2047,10 +2049,12 @@ void LLFace::resetVirtualSize()
F32 LLFace::getTextureVirtualSize()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
F32 radius;
F32 cos_angle_to_view_dir;
bool in_frustum = calcPixelArea(cos_angle_to_view_dir, radius);
if (mPixelArea < F_ALMOST_ZERO || !in_frustum)
{
setVirtualSize(0.f) ;

View File

@ -530,6 +530,9 @@ void LLGLTexMemBar::draw()
F64 raw_image_bytes_MB = raw_image_bytes / (1024.0 * 1024.0);
F64 saved_raw_image_bytes_MB = saved_raw_image_bytes / (1024.0 * 1024.0);
F64 aux_raw_image_bytes_MB = aux_raw_image_bytes / (1024.0 * 1024.0);
F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 1024.0 * 1.3333f; // add 33% for mipmaps
F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 1024.0;
F64 render_bytes_alloc = LLRenderTarget::sBytesAllocated / 1024.0 / 1024.0;
//----------------------------------------------------------------------------
LLGLSUIDefault gls_ui;
@ -559,7 +562,7 @@ void LLGLTexMemBar::draw()
// draw a background above first line.... no idea where the rest of the background comes from for the below text
gGL.color4f(0.f, 0.f, 0.f, 0.25f);
gl_rect_2d(-10, getRect().getHeight() + line_height + 1, getRect().getWidth()+2, getRect().getHeight()+2);
gl_rect_2d(-10, getRect().getHeight() + line_height*2 + 1, getRect().getWidth()+2, getRect().getHeight()+2);
text = llformat("Est. Free: %d MB Sys Free: %d MB FBO: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
(S32)LLViewerTexture::sFreeVRAMMegabytes,
@ -568,12 +571,20 @@ void LLGLTexMemBar::draw()
discard_bias,
cache_usage,
cache_max_usage);
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*7,
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*8,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
text = llformat("Images: %d Raw: %d (%.2f MB) Saved: %d (%.2f MB) Aux: %d (%.2f MB)", image_count, raw_image_count, raw_image_bytes_MB,
saved_raw_image_count, saved_raw_image_bytes_MB,
aux_raw_image_count, aux_raw_image_bytes_MB);
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height * 7,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
text = llformat("Textures: %.2f MB Vertex: %.2f MB Render: %.2f MB Total: %.2f MB",
texture_bytes_alloc,
vertex_bytes_alloc,
render_bytes_alloc,
texture_bytes_alloc+vertex_bytes_alloc+render_bytes_alloc);
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height * 6,
text_color, LLFontGL::LEFT, LLFontGL::TOP);

View File

@ -376,6 +376,7 @@ void LLViewerAssetStorage::queueRequestHttp(
bool duplicate,
bool is_priority)
{
LL_PROFILE_ZONE_SCOPED;
LL_DEBUGS("ViewerAsset") << "Request asset via HTTP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL;
bool with_http = true;

View File

@ -89,7 +89,7 @@ S32 LLViewerTexture::sRawCount = 0;
S32 LLViewerTexture::sAuxCount = 0;
LLFrameTimer LLViewerTexture::sEvaluationTimer;
F32 LLViewerTexture::sDesiredDiscardBias = 0.f;
F32 LLViewerTexture::sDesiredDiscardScale = 1.1f;
S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size
const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64;
const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez;
@ -513,15 +513,18 @@ void LLViewerTexture::updateClass()
F32 target = llmax(budget - 512.f, MIN_VRAM_BUDGET);
sFreeVRAMMegabytes = target - used;
F32 over_pct = llmax((used-target) / target, 0.f);
F32 over_pct = (used - target) / target;
bool is_low = over_pct > 0.f;
if (isSystemMemoryLow())
{
is_low = true;
// System RAM is low -> ramp up discard bias over time to free memory
if (sEvaluationTimer.getElapsedTimeF32() > MEMORY_CHECK_WAIT_TIME)
{
static LLCachedControl<F32> low_mem_min_discard_increment(gSavedSettings, "RenderLowMemMinDiscardIncrement", .1f);
sDesiredDiscardBias += llmax(low_mem_min_discard_increment, over_pct);
sDesiredDiscardBias += (F32) low_mem_min_discard_increment * (F32) gFrameIntervalSeconds;
sEvaluationTimer.reset();
}
}
@ -529,12 +532,28 @@ void LLViewerTexture::updateClass()
{
sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct);
if (sDesiredDiscardBias > 1.f)
if (sDesiredDiscardBias > 1.f && over_pct < 0.f)
{
sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01;
}
}
static bool was_low = false;
if (is_low && !was_low)
{
LL_WARNS() << "Low system memory detected, emergency downrezzing off screen textures" << LL_ENDL;
sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f);
for (auto image : gTextureList)
{
gTextureList.updateImageDecodePriority(image);
}
}
was_low = is_low;
sDesiredDiscardBias = llclamp(sDesiredDiscardBias, 1.f, 3.f);
LLViewerTexture::sFreezeImageUpdates = false;
}
@ -615,16 +634,15 @@ void LLViewerTexture::init(bool firstinit)
mParcelMedia = NULL;
memset(&mNumVolumes, 0, sizeof(U32)* LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
mFaceList[LLRender::DIFFUSE_MAP].clear();
mFaceList[LLRender::NORMAL_MAP].clear();
mFaceList[LLRender::SPECULAR_MAP].clear();
mNumFaces[LLRender::DIFFUSE_MAP] =
mNumFaces[LLRender::NORMAL_MAP] =
mNumFaces[LLRender::SPECULAR_MAP] = 0;
mVolumeList[LLRender::LIGHT_TEX].clear();
mVolumeList[LLRender::SCULPT_TEX].clear();
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; i++)
{
mNumFaces[i] = 0;
mFaceList[i].clear();
}
mMainQueue = LL::WorkQueue::getInstance("mainloop");
mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
}
@ -1608,7 +1626,11 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
}
else
{
gTextureList.mCreateTextureList.insert(this);
if (!mCreatePending)
{
mCreatePending = true;
gTextureList.mCreateTextureList.push(this);
}
}
}
}
@ -1632,13 +1654,12 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height)
void LLViewerFetchedTexture::setDebugText(const std::string& text)
{
for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
{
llassert(mNumFaces[ch] <= mFaceList[ch].size());
for (U32 i = 0; i < mNumFaces[ch]; i++)
for (S32 fi = 0; fi < getNumFaces(i); ++fi)
{
LLFace* facep = mFaceList[ch][i];
LLFace* facep = (*(getFaceList(i)))[fi];
if (facep)
{
LLDrawable* drawable = facep->getDrawable();
@ -1651,10 +1672,15 @@ void LLViewerFetchedTexture::setDebugText(const std::string& text)
}
}
extern bool gCubeSnapshot;
//virtual
void LLViewerFetchedTexture::processTextureStats()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
llassert(!gCubeSnapshot); // should only be called when the main camera is active
llassert(!LLPipeline::sShadowRender);
if(mFullyLoaded)
{
if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more
@ -2859,6 +2885,8 @@ void LLViewerLODTexture::processTextureStats()
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
updateVirtualSize();
bool did_downscale = false;
static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
{ // restrict texture resolution to download based on RenderMaxTextureResolution
@ -2916,10 +2944,7 @@ void LLViewerLODTexture::processTextureStats()
mDiscardVirtualSize = mMaxVirtualSize;
mCalculatedDiscardLevel = discard_level;
}
if (mBoostLevel < LLGLTexture::BOOST_SCULPTED)
{
discard_level *= sDesiredDiscardScale; // scale (default 1.1f)
}
discard_level = floorf(discard_level);
F32 min_discard = 0.f;
@ -2945,10 +2970,9 @@ void LLViewerLODTexture::processTextureStats()
//
S32 current_discard = getDiscardLevel();
if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED &&
current_discard >= 0)
if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED)
{
if (current_discard < (mDesiredDiscardLevel-1) && !mForceToSaveRawImage)
if (current_discard < mDesiredDiscardLevel && !mForceToSaveRawImage)
{ // should scale down
scaleDown();
}
@ -2968,9 +2992,6 @@ void LLViewerLODTexture::processTextureStats()
mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel);
}
// decay max virtual size over time
mMaxVirtualSize *= 0.8f;
// selection manager will immediately reset BOOST_SELECTED but never unsets it
// unset it immediately after we consume it
if (getBoostLevel() == BOOST_SELECTED)
@ -2979,14 +3000,22 @@ void LLViewerLODTexture::processTextureStats()
}
}
extern LLGLSLShader gCopyProgram;
bool LLViewerLODTexture::scaleDown()
{
if (mGLTexturep.isNull())
if (mGLTexturep.isNull() || !mGLTexturep->getHasGLTexture())
{
return false;
}
return mGLTexturep->scaleDown(mDesiredDiscardLevel);
if (!mDownScalePending)
{
mDownScalePending = true;
gTextureList.mDownScaleQueue.push(this);
}
return true;
}
//----------------------------------------------------------------------------------------------

View File

@ -37,6 +37,7 @@
#include "llmetricperformancetester.h"
#include "httpcommon.h"
#include "workqueue.h"
#include "gltf/common.h"
#include <map>
#include <list>
@ -102,7 +103,6 @@ public:
DYNAMIC_TEXTURE,
FETCHED_TEXTURE,
LOD_TEXTURE,
ATLAS_TEXTURE,
INVALID_TEXTURE_TYPE
};
@ -173,6 +173,15 @@ public:
LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;}
/*virtual*/ void updateBindStatsForTester() ;
struct MaterialEntry
{
S32 mIndex = LL::GLTF::INVALID_INDEX;
std::shared_ptr<LL::GLTF::Asset> mAsset;
};
typedef std::vector<MaterialEntry> material_list_t;
material_list_t mMaterialList; // reverse pointer pointing to LL::GLTF::Materials using this image as texture
protected:
void cleanup() ;
void init(bool firstinit) ;
@ -214,7 +223,6 @@ public:
static S32 sAuxCount;
static LLFrameTimer sEvaluationTimer;
static F32 sDesiredDiscardBias;
static F32 sDesiredDiscardScale;
static S32 sMaxSculptRez ;
static U32 sMinLargeImageSize ;
static U32 sMaxSmallImageSize ;
@ -414,6 +422,9 @@ public:
/*virtual*/bool isActiveFetching() override; //is actively in fetching by the fetching pipeline.
bool mCreatePending = false; // if true, this is in gTextureList.mCreateTextureList
mutable bool mDownScalePending = false; // if true, this is in gTextureList.mDownScaleQueue
protected:
S32 getCurrentDiscardLevelForFetching() ;
void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
@ -424,11 +435,6 @@ private:
void saveRawImage() ;
//for atlas
void resetFaceAtlas() ;
void invalidateAtlas(bool rebuild_geom) ;
bool insertToAtlas() ;
private:
bool mFullyLoaded;
bool mInDebug;
@ -539,9 +545,10 @@ public:
/*virtual*/ void processTextureStats();
bool isUpdateFrozen() ;
bool scaleDown();
private:
void init(bool firstinit) ;
bool scaleDown() ;
private:
F32 mDiscardVirtualSize; // Virtual size used to calculate desired discard

View File

@ -70,6 +70,8 @@ S32 LLViewerTextureList::sNumImages = 0;
LLViewerTextureList gTextureList;
extern LLGLSLShader gCopyProgram;
ETexListType get_element_type(S32 priority)
{
return (priority == LLViewerFetchedTexture::BOOST_ICON || priority == LLViewerFetchedTexture::BOOST_THUMBNAIL) ? TEX_LIST_SCALE : TEX_LIST_STANDARD;
@ -352,8 +354,11 @@ void LLViewerTextureList::shutdown()
mCallbackList.clear();
// Flush all of the references
mLoadingStreamList.clear();
mCreateTextureList.clear();
while (!mCreateTextureList.empty())
{
mCreateTextureList.front()->mCreatePending = false;
mCreateTextureList.pop();
}
mFastCacheList.clear();
mUUIDMap.clear();
@ -897,14 +902,6 @@ void LLViewerTextureList::clearFetchingRequests()
}
}
static void touch_texture(LLViewerFetchedTexture* tex, F32 vsize)
{
if (tex)
{
tex->addTextureStats(vsize);
}
}
extern bool gCubeSnapshot;
void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imagep)
@ -921,58 +918,67 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
static LLCachedControl<F32> texture_scale_min(gSavedSettings, "TextureScaleMinAreaFactor", 0.04f);
static LLCachedControl<F32> texture_scale_max(gSavedSettings, "TextureScaleMaxAreaFactor", 25.f);
if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE)
{ // reset max virtual size for unboosted LOD_TEXTURES
// this is an alternative to decaying mMaxVirtualSize over time
// that keeps textures from continously downrezzing and uprezzing in the background
imagep->mMaxVirtualSize = 0.f;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
{
for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
for (S32 fi = 0; fi < imagep->getNumFaces(i); ++fi)
{
for (S32 fi = 0; fi < imagep->getNumFaces(i); ++fi)
LLFace* face = (*(imagep->getFaceList(i)))[fi];
if (face && face->getViewerObject())
{
LLFace* face = (*(imagep->getFaceList(i)))[fi];
F32 radius;
F32 cos_angle_to_view_dir;
bool in_frustum = face->calcPixelArea(cos_angle_to_view_dir, radius);
static LLCachedControl<F32> bias_unimportant_threshold(gSavedSettings, "TextureBiasUnimportantFactor", 0.25f);
F32 vsize = face->getPixelArea();
if (face && face->getViewerObject() && face->getTextureEntry())
{
F32 radius;
F32 cos_angle_to_view_dir;
BOOL in_frustum = face->calcPixelArea(cos_angle_to_view_dir, radius);
static LLCachedControl<F32> bias_unimportant_threshold(gSavedSettings, "TextureBiasUnimportantFactor", 0.25f);
F32 vsize = face->getPixelArea();
// Scale desired texture resolution higher or lower depending on texture scale
//
// Minimum usage examples: a 1024x1024 texture with aplhabet, runing string
// shows one letter at a time
//
// Maximum usage examples: huge chunk of terrain repeats texture
const LLTextureEntry* te = face->getTextureEntry();
F32 min_scale = te ? llmin(fabsf(te->getScaleS()), fabsf(te->getScaleT())) : 1.f;
min_scale = llclamp(min_scale * min_scale, texture_scale_min(), texture_scale_max());
vsize /= min_scale;
// Scale desired texture resolution higher or lower depending on texture scale
//
// Minimum usage examples: a 1024x1024 texture with aplhabet, runing string
// shows one letter at a time
//
// Maximum usage examples: huge chunk of terrain repeats texture
const LLTextureEntry* te = face->getTextureEntry();
F32 min_scale = te ? llmin(fabsf(te->getScaleS()), fabsf(te->getScaleT())) : 1.f;
min_scale = llclamp(min_scale*min_scale, texture_scale_min(), texture_scale_max());
// if bias is > 2, apply to on-screen textures as well
bool apply_bias = LLViewerTexture::sDesiredDiscardBias > 2.f;
vsize /= min_scale;
if (!in_frustum || !face->getDrawable()->isVisible() || face->getImportanceToCamera() < bias_unimportant_threshold)
{ // further reduce by discard bias when off screen or occluded
vsize /= LLViewerTexture::sDesiredDiscardBias;
}
// if a GLTF material is present, ignore that face
// as far as this texture stats go, but update the GLTF material
// stats
LLFetchedGLTFMaterial* mat = te ? (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial() : nullptr;
llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(te->getGLTFRenderMaterial()) != nullptr);
if (mat)
{
touch_texture(mat->mBaseColorTexture, vsize);
touch_texture(mat->mNormalTexture, vsize);
touch_texture(mat->mMetallicRoughnessTexture, vsize);
touch_texture(mat->mEmissiveTexture, vsize);
}
else
{
imagep->addTextureStats(vsize);
}
// apply bias to off screen objects or objects that are small on screen all the time
if (!in_frustum || !face->getDrawable()->isVisible() || face->getImportanceToCamera() < bias_unimportant_threshold)
{ // further reduce by discard bias when off screen or occluded
apply_bias = true;
}
if (apply_bias)
{
F32 bias = powf(4, LLViewerTexture::sDesiredDiscardBias - 1.f);
bias = llround(bias);
vsize /= bias;
}
imagep->addTextureStats(vsize);
}
}
}
// make sure to addTextureStats for any spotlights that are using this texture
for (S32 vi = 0; vi < imagep->getNumVolumes(LLRender::LIGHT_TEX); ++vi)
{
LLVOVolume* volume = (*imagep->getVolumeList(LLRender::LIGHT_TEX))[vi];
volume->updateSpotLightPriority();
}
//imagep->setDebugText(llformat("%.3f - %d", sqrtf(imagep->getMaxVirtualSize()), imagep->getBoostLevel()));
F32 lazy_flush_timeout = 30.f; // stop decoding
@ -1066,22 +1072,65 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
//
LLTimer create_timer;
image_list_t::iterator enditer = mCreateTextureList.begin();
for (image_list_t::iterator iter = mCreateTextureList.begin();
iter != mCreateTextureList.end();)
if (!mDownScaleQueue.empty() && gPipeline.mDownResMap.isComplete())
{
image_list_t::iterator curiter = iter++;
enditer = iter;
LLViewerFetchedTexture *imagep = *curiter;
// just in case we downres textures, bind downresmap and copy program
gPipeline.mDownResMap.bindTarget();
gCopyProgram.bind();
gPipeline.mScreenTriangleVB->setBuffer();
// give time to downscaling first -- if mDownScaleQueue is not empty, we're running out of memory and need
// to free up memory by discarding off screen textures quickly
// do at least 5 and make sure we don't get too far behind even if it violates
// the time limit. If we don't downscale quickly the viewer will hit swap and may
// freeze.
S32 min_count = (S32)mCreateTextureList.size() / 20 + 5;
while (!mDownScaleQueue.empty())
{
LLViewerFetchedTexture* image = mDownScaleQueue.front();
llassert(image->mDownScalePending);
LLImageGL* img = image->getGLTexture();
if (img && img->getHasGLTexture())
{
img->scaleDown(image->getDesiredDiscardLevel());
}
image->mDownScalePending = false;
mDownScaleQueue.pop();
if (create_timer.getElapsedTimeF32() > max_time && --min_count <= 0)
{
break;
}
}
gCopyProgram.unbind();
gPipeline.mDownResMap.flush();
}
// do at least 5 and make sure we don't get too far behind even if it violates
// the time limit. Textures pending creation have a copy of their texture data
// in system memory, so we don't want to let them pile up.
S32 min_count = (S32) mCreateTextureList.size() / 20 + 5;
while (!mCreateTextureList.empty())
{
LLViewerFetchedTexture *imagep = mCreateTextureList.front();
llassert(imagep->mCreatePending);
imagep->createTexture();
imagep->postCreateTexture();
imagep->mCreatePending = false;
mCreateTextureList.pop();
if (create_timer.getElapsedTimeF32() > max_time)
if (create_timer.getElapsedTimeF32() > max_time && --min_count <= 0)
{
break;
}
}
mCreateTextureList.erase(mCreateTextureList.begin(), enditer);
return create_timer.getElapsedTimeF32();
}
@ -1124,7 +1173,10 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
removeImageFromList(imagep);
}
imagep->processTextureStats();
if (!gCubeSnapshot)
{ // never call processTextureStats in a cube snapshot
imagep->processTextureStats();
}
imagep->sMaxVirtualSize = LLViewerFetchedTexture::sMaxVirtualSize;
addImageToList(imagep);
@ -1134,6 +1186,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
typedef std::vector<LLPointer<LLViewerFetchedTexture> > entries_list_t;
entries_list_t entries;

View File

@ -144,12 +144,13 @@ public:
void clearFetchingRequests();
void setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level);
private:
// do some book keeping on the specified texture
// - updates decode priority
// - updates desired discard level
// - cleans up textures that haven't been referenced in awhile
void updateImageDecodePriority(LLViewerFetchedTexture* imagep);
private:
F32 updateImagesCreateTextures(F32 max_time);
F32 updateImagesFetchTextures(F32 max_time);
void updateImagesUpdateStats();
@ -211,8 +212,14 @@ private:
public:
typedef std::unordered_set<LLPointer<LLViewerFetchedTexture> > image_list_t;
image_list_t mLoadingStreamList;
image_list_t mCreateTextureList;
typedef std::queue<LLPointer<LLViewerFetchedTexture> > image_queue_t;
// images that have been loaded but are waiting to be uploaded to GL
image_queue_t mCreateTextureList;
// images that must be downscaled quickly so we don't run out of memory
image_queue_t mDownScaleQueue;
image_list_t mCallbackList;
image_list_t mFastCacheList;

View File

@ -451,6 +451,9 @@ void LLVOGrass::plantBlades()
face->setVertexBuffer(NULL);
face->setTEOffset(0);
face->mCenterLocal = mPosition + mRegionp->getOriginAgent();
const LLVector4a* ext = mDrawable->getSpatialExtents();
face->mExtents[0] = ext[0];
face->mExtents[1] = ext[1];
}
mDepth = (face->mCenterLocal - LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis();

View File

@ -461,9 +461,7 @@ void LLVOTree::updateTextures()
{
setDebugText(llformat("%4.0f", (F32) sqrt(mPixelArea)));
}
mTreeImagep->addTextureStats(mPixelArea);
}
}
@ -479,7 +477,7 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
// Just a placeholder for an actual object...
LLFace *facep = mDrawable->addFace(poolp, mTreeImagep);
facep->setSize(1, 3);
facep->setTexture(LLRender::DIFFUSE_MAP, mTreeImagep);
updateRadius();
return mDrawable;
@ -1169,6 +1167,10 @@ void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
LLVector4a pos;
pos.load3(center.mV);
mDrawable->setPositionGroup(pos);
LLFace* facep = mDrawable->getFace(0);
facep->mExtents[0] = newMin;
facep->mExtents[1] = newMax;
}
bool LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp,

View File

@ -5745,18 +5745,23 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
continue;
}
#if 0
#if LL_RELEASE_WITH_DEBUG_INFO
const LLUUID pbr_id( "49c88210-7238-2a6b-70ac-92d4f35963cf" );
const LLUUID obj_id( vobj->getID() );
bool is_pbr = (obj_id == pbr_id);
#else
bool is_pbr = false;
#endif
#else
LLGLTFMaterial *gltf_mat = facep->getTextureEntry()->getGLTFRenderMaterial();
LLFetchedGLTFMaterial *gltf_mat = (LLFetchedGLTFMaterial*) facep->getTextureEntry()->getGLTFRenderMaterial();
bool is_pbr = gltf_mat != nullptr;
#endif
if (is_pbr)
{
// tell texture streaming system to ignore blinn-phong textures
facep->setTexture(LLRender::DIFFUSE_MAP, nullptr);
facep->setTexture(LLRender::NORMAL_MAP, nullptr);
facep->setTexture(LLRender::SPECULAR_MAP, nullptr);
// let texture streaming system know about PBR textures
facep->setTexture(LLRender::BASECOLOR_MAP, gltf_mat->mBaseColorTexture);
facep->setTexture(LLRender::GLTF_NORMAL_MAP, gltf_mat->mNormalTexture);
facep->setTexture(LLRender::METALLIC_ROUGHNESS_MAP, gltf_mat->mMetallicRoughnessTexture);
facep->setTexture(LLRender::EMISSIVE_MAP, gltf_mat->mEmissiveTexture);
}
//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
// batch, it will recover its vertex buffer reference from the spatial group

View File

@ -865,6 +865,10 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
const U32 post_color_fmt = post_hdr ? GL_RGBA16F : GL_RGBA;
mPostMap.allocate(resX, resY, post_color_fmt);
// used to scale down textures
// See LLViwerTextureList::updateImagesCreateTextures and LLImageGL::scaleDown
mDownResMap.allocate(4, 4, GL_RGBA);
//HACK make screenbuffer allocations start failing after 30 seconds
if (gSavedSettings.getBOOL("SimulateFBOFailure"))
{
@ -1111,6 +1115,8 @@ void LLPipeline::releaseGLBuffers()
mPostMap.release();
mDownResMap.release();
for (U32 i = 0; i < 3; i++)
{
mGlow[i].release();

View File

@ -725,6 +725,9 @@ public:
// tonemapped and gamma corrected render ready for post
LLRenderTarget mPostMap;
// downres scratch space for GPU downscaling of textures
LLRenderTarget mDownResMap;
LLCullResult mSky;
LLCullResult mReflectedObjects;
LLCullResult mRefractedObjects;