phoenix-firestorm/indra/newview/llviewerdisplay.cpp

1908 lines
65 KiB
C++

/**
* @file llviewerdisplay.cpp
* @brief LLViewerDisplay class implementation
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llviewerdisplay.h"
#include "llgl.h"
#include "llrender.h"
#include "llglheaders.h"
#include "llgltfmateriallist.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llviewercontrol.h"
#include "llcoord.h"
#include "llcriticaldamp.h"
#include "lldir.h"
#include "lldynamictexture.h"
#include "lldrawpoolalpha.h"
#include "llfeaturemanager.h"
//#include "llfirstuse.h"
#include "llhudmanager.h"
#include "llimagepng.h"
#include "llmemory.h"
#include "llselectmgr.h"
#include "llsky.h"
#include "llstartup.h"
#include "lltoolfocus.h"
#include "lltoolmgr.h"
#include "lltooldraganddrop.h"
#include "lltoolpie.h"
#include "lltracker.h"
#include "lltrans.h"
#include "llui.h"
#include "llviewercamera.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llvograss.h"
#include "llworld.h"
#include "pipeline.h"
#include "llspatialpartition.h"
#include "llappviewer.h"
#include "llstartup.h"
#include "llviewershadermgr.h"
#include "llfasttimer.h"
#include "llfloatertools.h"
#include "llviewertexturelist.h"
#include "llfocusmgr.h"
#include "llcubemap.h"
#include "llviewerregion.h"
#include "lldrawpoolwater.h"
#include "lldrawpoolbump.h"
#include "llpostprocess.h"
#include "llscenemonitor.h"
#include "llenvironment.h"
#include "llperfstats.h"
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
#include "llvisualeffect.h"
#include "rlvactions.h"
#include "rlvlocks.h"
// [/RLVa:KB]
#include "llpresetsmanager.h"
#include "fsdata.h"
extern LLPointer<LLViewerTexture> gStartTexture;
extern bool gShiftFrame;
LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
// used to toggle renderer back on after teleport
bool gTeleportDisplay = false;
LLFrameTimer gTeleportDisplayTimer;
LLFrameTimer gTeleportArrivalTimer;
const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
// <FS:Ansariel> Draw Distance stepping; originally based on SpeedRez by Henri Beauchamp, licensed under LGPL
F32 gSavedDrawDistance = 0.0f;
F32 gLastDrawDistanceStep = 0.0f;
// <FS:Ansariel> FIRE-12004: Attachments getting lost on TP
LLFrameTimer gPostTeleportFinishKillObjectDelayTimer;
bool gForceRenderLandFence = false;
bool gDisplaySwapBuffers = false;
bool gDepthDirty = false;
bool gResizeScreenTexture = false;
bool gResizeShadowTexture = false;
bool gWindowResized = false;
bool gSnapshot = false;
bool gCubeSnapshot = false;
bool gSnapshotNoPost = false;
bool gShaderProfileFrame = false;
// This is how long the sim will try to teleport you before giving up.
const F32 TELEPORT_EXPIRY = 15.0f;
// Additional time (in seconds) to wait per attachment
const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
U32 gRecentFrameCount = 0; // number of 'recent' frames
LLFrameTimer gRecentFPSTime;
LLFrameTimer gRecentMemoryTime;
LLFrameTimer gAssetStorageLogTime;
// Rendering stuff
void pre_show_depth_buffer();
void post_show_depth_buffer();
void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
void swap();
void render_hud_attachments();
void render_ui_3d();
void render_ui_2d();
void render_disconnected_background();
void display_startup()
{
if ( !gViewerWindow
|| !gViewerWindow->getActive()
|| !gViewerWindow->getWindow()->getVisible()
|| gViewerWindow->getWindow()->getMinimized()
|| gNonInteractive)
{
return;
}
gPipeline.updateGL();
// Written as branch to appease GCC which doesn't like different
// pointer types across ternary ops
//
if (!LLViewerFetchedTexture::sWhiteImagep.isNull())
{
LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
}
LLGLSDefault gls_default;
// Required for HTML update in login screen
static S32 frame_count = 0;
LLGLState::checkStates();
if (frame_count++ > 1) // make sure we have rendered a frame first
{
LLViewerDynamicTexture::updateAllInstances();
}
else
{
LL_DEBUGS("Window") << "First display_startup frame" << LL_ENDL;
}
LLGLState::checkStates();
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
LLGLSUIDefault gls_ui;
gPipeline.disableLights();
if (gViewerWindow)
gViewerWindow->setup2DRender();
if (gViewerWindow)
gViewerWindow->draw();
gGL.flush();
LLVertexBuffer::unbind();
LLGLState::checkStates();
if (gViewerWindow && gViewerWindow->getWindow())
gViewerWindow->getWindow()->swapBuffers();
glClear(GL_DEPTH_BUFFER_BIT);
}
void display_update_camera()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update Camera");
// TODO: cut draw distance down if customizing avatar?
// TODO: cut draw distance on per-parcel basis?
// Cut draw distance in half when customizing avatar,
// but on the viewer only.
F32 final_far = gAgentCamera.mDrawDistance;
if (gCubeSnapshot)
{
final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance");
}
else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
{
final_far *= 0.5f;
}
// <FS:CR> Aurora sim
if(LLWorld::getInstance()->getLockedDrawDistance())
{
//Reset the draw distance and do not update with the new val
final_far = LLViewerCamera::getInstance()->getFar();
}
// </FS:CR> Aurora sim
LLViewerCamera::getInstance()->setFar(final_far);
gViewerWindow->setup3DRender();
if (!gCubeSnapshot)
{
// Update land visibility too
LLWorld::getInstance()->setLandFarClip(final_far);
}
}
// Write some stats to LL_INFOS()
void display_stats()
{
LL_PROFILE_ZONE_SCOPED;
const F32 FPS_LOG_FREQUENCY = 10.f;
if (gRecentFPSTime.getElapsedTimeF32() >= FPS_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
F32 fps = gRecentFrameCount / FPS_LOG_FREQUENCY;
LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL;
gRecentFrameCount = 0;
gRecentFPSTime.reset();
}
// <FS:Ansariel> gSavedSettings replacement
//F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
static LLCachedControl<F32> memoryLogFrequency(gSavedSettings, "MemoryLogFrequency");
F32 mem_log_freq = (F32)memoryLogFrequency;
// </FS:Ansariel>
if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS());
U32Megabytes memory = gMemoryAllocated;
LL_INFOS() << "MEMORY: " << memory << LL_ENDL;
LLMemory::logMemoryInfo(true) ;
gRecentMemoryTime.reset();
}
const F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f;
if (gAssetStorageLogTime.getElapsedTimeF32() >= ASSET_STORAGE_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
gAssetStorageLogTime.reset();
gAssetStorage->logAssetStorageInfo();
}
}
static void update_tp_display(bool minimized)
{
static LLCachedControl<F32> teleport_arrival_delay(gSavedSettings, "TeleportArrivalDelay");
static LLCachedControl<F32> teleport_local_delay(gSavedSettings, "TeleportLocalDelay");
S32 attach_count = 0;
if (isAgentAvatarValid())
{
attach_count = gAgentAvatarp->getAttachmentCount();
}
F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
if (gAgent.getTeleportState() != LLAgent::TELEPORT_START && teleport_percent > 100.f)
{
// Give up. Don't keep the UI locked forever.
LL_WARNS("Teleport") << "Giving up on teleport. elapsed time " << teleport_elapsed << " exceeds max time " << teleport_save_time << LL_ENDL;
gAgent.setTeleportState(LLAgent::TELEPORT_NONE);
gAgent.setTeleportMessage(std::string());
}
// Make sure the TP progress panel gets hidden in case the viewer window
// is minimized *during* a TP. HB
if (minimized)
{
gViewerWindow->setShowProgress(false, false);
}
const std::string& message = gAgent.getTeleportMessage();
switch (gAgent.getTeleportState())
{
case LLAgent::TELEPORT_PENDING:
{
gTeleportDisplayTimer.reset();
const std::string& msg = LLAgent::sTeleportProgressMessages["pending"];
if (!minimized)
{
gViewerWindow->setShowProgress(true, !gSavedSettings.getBOOL("FSDisableTeleportScreens"));
gViewerWindow->setProgressPercent(llmin(teleport_percent, 0.0f));
gViewerWindow->setProgressString(msg);
}
gAgent.setTeleportMessage(msg);
break;
}
case LLAgent::TELEPORT_START:
{
// Transition to REQUESTED. Viewer has sent some kind
// of TeleportRequest to the source simulator
// Reset view angle if in mouselook. Fixes camera angle getting stuck on teleport. -Zi
if (gAgentCamera.cameraMouselook())
{
// If someone knows how to call "View.ZoomDefault" by hand, we should do that instead of
// replicating the behavior here. -Zi
LLViewerCamera::instance().setDefaultFOV(DEFAULT_FIELD_OF_VIEW);
if (gSavedSettings.getBOOL("FSResetCameraOnTP"))
{
gSavedSettings.setF32("CameraAngle", LLViewerCamera::instance().getView()); // FS:LO Dont reset rightclick zoom when we teleport however. Fixes FIRE-6246.
}
// also, reset the marker for "currently zooming" in the mouselook zoom settings. -Zi
LLVector3 vTemp = gSavedSettings.getVector3("_NACL_MLFovValues");
vTemp.mV[VZ] = 0.0f;
gSavedSettings.setVector3("_NACL_MLFovValues", vTemp);
}
gTeleportDisplayTimer.reset();
const std::string& msg = LLAgent::sTeleportProgressMessages["requesting"];
LL_INFOS("Teleport") << "A teleport request has been sent, setting state to TELEPORT_REQUESTED" << LL_ENDL;
gAgent.setTeleportState(LLAgent::TELEPORT_REQUESTED);
gAgent.setTeleportMessage(msg);
FSData::instance().selectNextMOTD();
if (!minimized)
{
gViewerWindow->setShowProgress(true, !gSavedSettings.getBOOL("FSDisableTeleportScreens"));
gViewerWindow->setProgressPercent(llmin(teleport_percent, 0.0f));
gViewerWindow->setProgressString(msg);
gViewerWindow->setProgressMessage(gAgent.mMOTD);
}
break;
}
case LLAgent::TELEPORT_REQUESTED:
// Waiting for source simulator to respond
if (!minimized)
{
gViewerWindow->setProgressPercent(llmin(teleport_percent, 37.5f));
gViewerWindow->setProgressString(message);
}
break;
case LLAgent::TELEPORT_MOVING:
// Viewer has received destination location from source simulator
if (!minimized)
{
gViewerWindow->setProgressPercent(llmin(teleport_percent, 75.f));
gViewerWindow->setProgressString(message);
}
break;
case LLAgent::TELEPORT_START_ARRIVAL:
// Transition to ARRIVING. Viewer has received avatar update, etc.,
// from destination simulator
gTeleportArrivalTimer.reset();
LL_INFOS("Teleport") << "Changing state to TELEPORT_ARRIVING" << LL_ENDL;
gAgent.setTeleportState(LLAgent::TELEPORT_ARRIVING);
gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["arriving"]);
gAgent.sheduleTeleportIM();
gTextureList.mForceResetTextureStats = true;
gAgentCamera.resetView(true, true);
if (!minimized)
{
gViewerWindow->setProgressCancelButtonVisible(false, LLTrans::getString("Cancel"));
gViewerWindow->setProgressPercent(75.f);
}
// <FS:Ansariel> FIRE-12004: Attachments getting lost on TP
gPostTeleportFinishKillObjectDelayTimer.reset();
break;
case LLAgent::TELEPORT_ARRIVING:
// Make the user wait while content "pre-caches"
{
F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / teleport_arrival_delay());
if (arrival_fraction > 1.f)
{
arrival_fraction = 1.f;
//LLFirstUse::useTeleport();
LL_INFOS("Teleport") << "arrival_fraction is " << arrival_fraction << " changing state to TELEPORT_NONE" << LL_ENDL;
gAgent.setTeleportState(LLAgent::TELEPORT_NONE);
}
if (!minimized)
{
gViewerWindow->setProgressCancelButtonVisible(false, LLTrans::getString("Cancel"));
gViewerWindow->setProgressPercent(arrival_fraction * 25.f + 75.f);
gViewerWindow->setProgressString(message);
}
break;
}
case LLAgent::TELEPORT_LOCAL:
// Short delay when teleporting in the same sim (progress screen active but not shown - did not
// fall-through from TELEPORT_START)
{
// <FS:CR> FIRE-8721 - Remove local teleport delay
//if (gTeleportDisplayTimer.getElapsedTimeF32() > teleport_local_delay())
// </FS:CR>
{
//LLFirstUse::useTeleport();
LL_INFOS("Teleport") << "State is local and gTeleportDisplayTimer " << gTeleportDisplayTimer.getElapsedTimeF32()
<< " exceeds teleport_local_delete " << teleport_local_delay
<< "; setting state to TELEPORT_NONE"
<< LL_ENDL;
gAgent.setTeleportState(LLAgent::TELEPORT_NONE);
}
break;
}
case LLAgent::TELEPORT_NONE:
// No teleport in progress
gViewerWindow->setShowProgress(false, false);
gTeleportDisplay = false;
}
}
// Paint the display!
void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Render");
LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering.
LLViewerCamera& camera = LLViewerCamera::instance(); // <FS:Ansariel> Factor out calls to getInstance
if (gWindowResized)
{ //skip render on frames where window has been resized
LL_DEBUGS("Window") << "Resizing window" << LL_ENDL;
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Resize Window");
gGL.flush();
glClear(GL_COLOR_BUFFER_BIT);
gViewerWindow->getWindow()->swapBuffers();
LLPipeline::refreshCachedSettings();
gPipeline.resizeScreenTexture();
gResizeScreenTexture = false;
gWindowResized = false;
return;
}
if (gResizeShadowTexture)
{ //skip render on frames where window has been resized
gPipeline.resizeShadowTexture();
gResizeShadowTexture = false;
}
gSnapshot = for_snapshot;
if (LLPipeline::sRenderDeferred)
{ //hack to make sky show up in deferred snapshots
for_snapshot = false;
}
LLGLSDefault gls_default;
LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
LLVertexBuffer::unbind();
LLGLState::checkStates();
gPipeline.disableLights();
// Don't draw if the window is hidden or minimized.
// In fact, must explicitly check the minimized state before drawing.
// Attempting to draw into a minimized window causes a GL error. JC
if ( !gViewerWindow->getActive()
|| !gViewerWindow->getWindow()->getVisible()
|| gViewerWindow->getWindow()->getMinimized()
|| gNonInteractive)
{
// Clean up memory the pools may have allocated
if (rebuild)
{
stop_glerror();
gPipeline.rebuildPools();
stop_glerror();
}
// <FS:ND> FIRE-15789; Make sure there's not backlog for thousands and thousands of beam objects
LLHUDObject::renderAllForTimer();
// </FS:ND>
stop_glerror();
gViewerWindow->returnEmptyPicks();
stop_glerror();
// We still need to update the teleport progress (to get changes done
// in TP states, else the sim does not get the messages signaling the
// agent's arrival). This fixes BUG-230616. HB
if (gTeleportDisplay)
{
// true = minimized, do not show/update the TP screen. HB
update_tp_display(true);
}
return;
}
gViewerWindow->checkSettings();
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Picking");
gViewerWindow->performPick();
}
LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
LLGLState::checkStates();
//////////////////////////////////////////////////////////
//
// Logic for forcing window updates if we're in drone mode.
//
// *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18
if (gHeadlessClient)
{
#if LL_WINDOWS
static F32 last_update_time = 0.f;
if ((gFrameTimeSeconds - last_update_time) > 1.f)
{
InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, false);
last_update_time = gFrameTimeSeconds;
}
#elif LL_DARWIN
// MBW -- Do something clever here.
#endif
// Not actually rendering, don't bother.
return;
}
//
// Bail out if we're in the startup state and don't want to try to
// render the world.
//
// <FS:Ansariel> Revert to original state to prevent flickering if login progress screen is disabled
//if (LLStartUp::getStartupState() < STATE_PRECACHE)
if (LLStartUp::getStartupState() < STATE_STARTED)
// </FS:Ansariel>
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
display_startup();
return;
}
if (gShaderProfileFrame)
{
LLGLSLShader::initProfile();
}
//LLGLState::verify(false);
/////////////////////////////////////////////////
//
// Update GL Texture statistics (used for discard logic?)
//
LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
stop_glerror();
LLImageGL::updateStats(gFrameTimeSeconds);
// <FS:CR> Aurora sim
//LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
static LLCachedControl<S32> avatarNameTagMode(gSavedSettings, "AvatarNameTagMode");
S32 RenderName = (S32)avatarNameTagMode;
if(RenderName > LLWorld::getInstance()->getAllowRenderName())//The most restricted gets set here
RenderName = LLWorld::getInstance()->getAllowRenderName();
LLVOAvatar::sRenderName = RenderName;
// <FS:CR> Aurora sim
// <FS:Ansariel> gSavedSettings replacement
//LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
static LLCachedControl<bool> nameTagShowGroupTitles(gSavedSettings, "NameTagShowGroupTitles");
LLVOAvatar::sRenderGroupTitles = (nameTagShowGroupTitles && LLVOAvatar::sRenderName);
// </FS:Ansariel>
gPipeline.mBackfaceCull = true;
gFrameCount++;
gRecentFrameCount++;
if (gFocusMgr.getAppHasFocus())
{
gForegroundFrameCount++;
}
//////////////////////////////////////////////////////////
//
// Display start screen if we're teleporting, and skip render
//
if (gTeleportDisplay)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Teleport Display");
LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
// Note: false = not minimized, do update the TP screen. HB
update_tp_display(false);
}
else if(LLAppViewer::instance()->logoutRequestSent())
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
if (percent_done > 100.f)
{
percent_done = 100.f;
}
if( LLApp::isExiting() )
{
percent_done = 100.f;
}
gViewerWindow->setProgressPercent( percent_done );
gViewerWindow->setProgressMessage(std::string());
}
else
if (gRestoreGL)
{
LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
if( percent_done > 100.f )
{
gViewerWindow->setShowProgress(false,false);
gRestoreGL = false;
}
else
{
if( LLApp::isExiting() )
{
percent_done = 100.f;
}
gViewerWindow->setProgressPercent( percent_done );
}
gViewerWindow->setProgressMessage(std::string());
}
// <FS::Ansariel> Draw Distance stepping; originally based on SpeedRez by Henri Beauchamp, licensed under LGPL
// Progressively increase draw distance after TP when required.
static LLCachedControl<F32> renderFarClip(gSavedSettings, "RenderFarClip");
if (gSavedDrawDistance > 0.0f && gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)
{
if (gLastDrawDistanceStep != renderFarClip())
{
LLPresetsManager::instance().setIsDrawDistanceSteppingActive(false);
gSavedDrawDistance = 0.0f;
gLastDrawDistanceStep = 0.0f;
gSavedSettings.setF32("FSSavedRenderFarClip", 0.0f);
}
if (gTeleportArrivalTimer.getElapsedTimeF32() >=
(F32)gSavedSettings.getU32("FSRenderFarClipSteppingInterval"))
{
gTeleportArrivalTimer.reset();
F32 current = gSavedSettings.getF32("RenderFarClip");
if (gSavedDrawDistance > current)
{
current *= 2.0f;
if (current > gSavedDrawDistance)
{
current = gSavedDrawDistance;
}
gSavedSettings.setF32("RenderFarClip", current);
gLastDrawDistanceStep = current;
}
if (current >= gSavedDrawDistance)
{
LLPresetsManager::instance().setIsDrawDistanceSteppingActive(false);
gSavedDrawDistance = 0.0f;
gLastDrawDistanceStep = 0.0f;
gSavedSettings.setF32("FSSavedRenderFarClip", 0.0f);
}
}
}
// </FS::Ansariel>
//////////////////////////
//
// Prepare for the next frame
//
/////////////////////////////
//
// Update the camera
//
//
LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
if (LLViewerCamera::instanceExists())
{
LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
}
//////////////////////////
//
// clear the next buffer
// (must follow dynamic texture writing since that uses the frame buffer)
//
if (gDisconnected)
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
render_ui();
swap();
}
//////////////////////////
//
// Set rendering options
//
//
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
stop_glerror();
///////////////////////////////////////
//
// Slam lighting parameters back to our defaults.
// Note that these are not the same as GL defaults...
stop_glerror();
gGL.setAmbientLightColor(LLColor4::white);
stop_glerror();
/////////////////////////////////////
//
// Render
//
// Actually push all of our triangles to the screen.
//
// do render-to-texture stuff here
if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
{
LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update Dynamic Textures");
if (LLViewerDynamicTexture::updateAllInstances())
{
gGL.setColorMask(true, true);
glClear(GL_DEPTH_BUFFER_BIT);
}
}
gViewerWindow->setup3DViewport();
gPipeline.resetFrameStats(); // Reset per-frame statistics.
if (!gDisconnected && !LLApp::isExiting())
{
// Render mirrors and associated hero probes before we render the rest of the scene.
// This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it.
if (gPipeline.RenderMirrors && !gSnapshot)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes");
gPipeline.mHeroProbeManager.update();
gPipeline.mHeroProbeManager.renderProbes();
}
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
{ //don't draw hud objects in this frame
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
}
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
{ //don't draw hud particles in this frame
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
}
stop_glerror();
display_update_camera();
stop_glerror();
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Env Update");
// update all the sky/atmospheric/water settings
LLEnvironment::instance().update(&camera); // <FS:Ansariel> Factor out calls to getInstance
}
// *TODO: merge these two methods
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("HUD Update");
LLHUDManager::getInstance()->updateEffects();
LLHUDObject::updateAll();
stop_glerror();
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update Geom");
const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds.value(); // 50 ms/second update time
gPipeline.createObjects(max_geom_update_time);
gPipeline.processPartitionQ();
gPipeline.updateGeom(max_geom_update_time);
stop_glerror();
}
gPipeline.updateGL();
stop_glerror();
LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
//Increment drawable frame counter
LLDrawable::incrementVisible();
LLSpatialGroup::sNoDelete = true;
LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
S32 occlusion = LLPipeline::sUseOcclusion;
if (gDepthDirty)
{ //depth buffer is invalid, don't overwrite occlusion state
LLPipeline::sUseOcclusion = llmin(occlusion, 1);
}
gDepthDirty = false;
LLGLState::checkStates();
static LLCullResult result;
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
gPipeline.updateCull(*LLViewerCamera::getInstance(), result);
stop_glerror();
LLGLState::checkStates();
LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2")
if (gResizeScreenTexture)
{
gPipeline.resizeScreenTexture();
gResizeScreenTexture = false;
}
gGL.setColorMask(true, true);
glClearColor(0,0,0,0);
LLGLState::checkStates();
if (!for_snapshot)
{
if (gFrameCount > 1 && !for_snapshot)
{ //for some reason, ATI 4800 series will error out if you
//try to generate a shadow before the first frame is through
gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
}
LLVertexBuffer::unbind();
LLGLState::checkStates();
glh::matrix4f proj = get_current_projection();
glh::matrix4f mod = get_current_modelview();
glViewport(0,0,512,512);
LLVOAvatar::updateImpostors();
set_current_projection(proj);
set_current_modelview(mod);
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.loadMatrix(proj.m);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(mod.m);
gViewerWindow->setup3DViewport();
LLGLState::checkStates();
}
glClear(GL_DEPTH_BUFFER_BIT);
}
//////////////////////////////////////
//
// Update images, using the image stats generated during object update/culling
//
// Can put objects onto the retextured list.
//
// Doing this here gives hardware occlusion queries extra time to complete
LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
{
LL_PROFILE_ZONE_NAMED("Update Images");
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Class");
LLViewerTexture::updateClass();
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Image Update Bump");
gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("List");
F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds.value(); // 50 ms/second decode time
max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
gTextureList.updateImages(max_image_decode_time);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("GLTF Materials Cleanup");
//remove dead gltf materials
gGLTFMaterialList.flushMaterials();
}
}
LLGLState::checkStates();
///////////////////////////////////
//
// StateSort
//
// Responsible for taking visible objects, and adding them to the appropriate draw orders.
// In the case of alpha objects, z-sorts them first.
// Also creates special lists for outlines and selected face rendering.
//
LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 4")
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
gPipeline.stateSort(camera, result); // <FS:Ansariel> Factor out calls to getInstance
stop_glerror();
if (rebuild)
{
//////////////////////////////////////
//
// rebuildPools
//
//
gPipeline.rebuildPools();
stop_glerror();
}
}
LLSceneMonitor::getInstance()->fetchQueryResult();
LLGLState::checkStates();
LLPipeline::sUseOcclusion = occlusion;
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT("update sky"); //LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY);
gSky.updateSky();
}
if(gUseWireframe)
{
glClearColor(0.5f, 0.5f, 0.5f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
}
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
//// render frontmost floater opaque for occlusion culling purposes
//LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
//// assumes frontmost floater with focus is opaque
//if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
//{
// gGL.matrixMode(LLRender::MM_MODELVIEW);
// gGL.pushMatrix();
// {
// gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
// gGL.loadIdentity();
// LLRect floater_rect = frontmost_floaterp->calcScreenRect();
// // deflate by one pixel so rounding errors don't occlude outside of floater extents
// floater_rect.stretch(-1);
// LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),
// (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
// (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
// (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
// floater_3d_rect.translate(-0.5f, -0.5f);
// gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
// gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
// gGL.color4fv(LLColor4::white.mV);
// gGL.begin(LLVertexBuffer::QUADS);
// {
// gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
// gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
// gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
// gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
// }
// gGL.end();
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// }
// gGL.popMatrix();
//}
LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
// <FS:CR> Aurora Sim
if (!LLWorld::getInstance()->getAllowRenderWater())
{
LLPipeline::sUnderWaterRender = false;
}
// </FS:CR> Aurora Sim
LLGLState::checkStates();
stop_glerror();
gGL.setColorMask(true, true);
if (LLPipeline::sRenderDeferred)
{
gPipeline.mRT->deferredScreen.bindTarget();
if (gUseWireframe)
{
F32 g = 0.5f;
glClearColor(g, g, g, 1.f);
}
else
{
glClearColor(1, 0, 1, 1);
}
gPipeline.mRT->deferredScreen.clear();
}
else
{
gPipeline.mRT->screen.bindTarget();
if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
{
const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
}
gPipeline.mRT->screen.clear();
}
gGL.setColorMask(true, false);
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom");
if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
&& !gRestoreGL)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
// <FS:Ansariel> gSavedSettings replacement
//if (gSavedSettings.getBOOL("RenderDepthPrePass"))
static LLCachedControl<bool> renderDepthPrePass(gSavedSettings, "RenderDepthPrePass");
if (renderDepthPrePass)
// </FS:Ansariel>
{
gGL.setColorMask(false, false);
static const U32 types[] = {
LLRenderPass::PASS_SIMPLE,
LLRenderPass::PASS_FULLBRIGHT,
LLRenderPass::PASS_SHINY
};
U32 num_types = LL_ARRAY_SIZE(types);
gOcclusionProgram.bind();
for (U32 i = 0; i < num_types; i++)
{
gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, false);
}
gOcclusionProgram.unbind();
}
gGL.setColorMask(true, true);
gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Texture Unbind");
for (S32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
{ //dummy cleanup of any currently bound textures
if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
{
gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
gGL.getTexUnit(i)->disable();
}
}
}
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mRT->deferredScreen : gPipeline.mRT->screen);
rt.flush();
if (LLPipeline::sRenderDeferred)
{
gPipeline.renderDeferredLighting();
}
LLPipeline::sUnderWaterRender = false;
{
//capture the frame buffer.
LLSceneMonitor::getInstance()->capture();
}
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
if (!for_snapshot)
{
render_ui();
swap();
}
LLSpatialGroup::sNoDelete = false;
gPipeline.clearReferences();
}
LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
stop_glerror();
display_stats();
LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
gShiftFrame = false;
if (gShaderProfileFrame)
{
gShaderProfileFrame = false;
LLGLSLShader::finishProfile();
}
}
// WIP simplified copy of display() that does minimal work
void display_cube_face()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Render Cube Face");
LL_PROFILE_GPU_ZONE("display cube face");
llassert(!gSnapshot);
llassert(!gTeleportDisplay);
llassert(LLStartUp::getStartupState() >= STATE_PRECACHE);
llassert(!LLAppViewer::instance()->logoutRequestSent());
llassert(!gRestoreGL);
bool rebuild = false;
LLGLSDefault gls_default;
LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
LLVertexBuffer::unbind();
gPipeline.disableLights();
gPipeline.mBackfaceCull = true;
gViewerWindow->setup3DViewport();
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
{ //don't draw hud objects in this frame
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
}
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
{ //don't draw hud particles in this frame
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
}
display_update_camera();
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Env Update");
// update all the sky/atmospheric/water settings
LLEnvironment::instance().update(LLViewerCamera::getInstance());
}
LLSpatialGroup::sNoDelete = true;
S32 occlusion = LLPipeline::sUseOcclusion;
LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
//gDepthDirty = true; //let "real" render pipe know it can't trust the depth buffer for occlusion data
static LLCullResult result;
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
gPipeline.updateCull(*LLViewerCamera::getInstance(), result);
gGL.setColorMask(true, true);
glClearColor(0, 0, 0, 0);
gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
glClear(GL_DEPTH_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
{
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
if (rebuild)
{
//////////////////////////////////////
//
// rebuildPools
//
//
gPipeline.rebuildPools();
stop_glerror();
}
}
LLPipeline::sUseOcclusion = occlusion;
LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
gGL.setColorMask(true, true);
gPipeline.mRT->deferredScreen.bindTarget();
if (gUseWireframe)
{
glClearColor(0.5f, 0.5f, 0.5f, 1.f);
}
else
{
glClearColor(1, 0, 1, 1);
}
gPipeline.mRT->deferredScreen.clear();
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
gPipeline.mRT->deferredScreen.flush();
gPipeline.renderDeferredLighting();
LLPipeline::sUnderWaterRender = false;
// Finalize scene
//gPipeline.renderFinalize();
LLSpatialGroup::sNoDelete = false;
gPipeline.clearReferences();
}
void render_hud_attachments()
{
LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_HUDS); // render time capture - Primary contributor to HUDs (though these end up in render batches)
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
glh::matrix4f current_proj = get_current_projection();
glh::matrix4f current_mod = get_current_modelview();
// clamp target zoom level to reasonable values
// gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c
gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f);
// [/RLVa:KB]
// smoothly interpolate current zoom level
gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.getAgentHUDTargetZoom(), LLSmoothInterpolation::getInterpolant(0.03f));
if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
{
LLPipeline::sRenderingHUDs = true;
LLCamera hud_cam = *LLViewerCamera::getInstance();
hud_cam.setOrigin(-1.f,0,0);
hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
LLViewerCamera::updateFrustumPlanes(hud_cam, true);
// <FS:Ansariel> gSavedSettings replacement
//bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
static LLCachedControl<bool> renderHUDParticles(gSavedSettings, "RenderHUDParticles");
bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && renderHUDParticles;
// </FS:Ansariel>
//only render hud objects
gPipeline.pushRenderTypeMask();
// turn off everything
gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
// turn on HUD
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
// turn on HUD particles
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
// if particles are off, turn off hud-particles as well
if (!render_particles)
{
// turn back off HUD particles
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
}
bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
if (has_ui)
{
gPipeline.toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
}
S32 use_occlusion = LLPipeline::sUseOcclusion;
LLPipeline::sUseOcclusion = 0;
//cull, sort, and render hud objects
static LLCullResult result;
LLSpatialGroup::sNoDelete = true;
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
gPipeline.updateCull(hud_cam, result, true);
// Toggle render types
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_PRE_WATER);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_MASK);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_GLTF_PBR);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_GLTF_PBR_ALPHA_MASK);
// Toggle render passes
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIAL);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_GLTF_PBR);
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK);
gPipeline.stateSort(hud_cam, result);
gPipeline.renderGeomPostDeferred(hud_cam);
LLSpatialGroup::sNoDelete = false;
//gPipeline.clearReferences();
render_hud_elements();
//restore type mask
gPipeline.popRenderTypeMask();
if (has_ui)
{
gPipeline.toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
}
LLPipeline::sUseOcclusion = use_occlusion;
LLPipeline::sRenderingHUDs = false;
}
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.popMatrix();
set_current_projection(current_proj);
set_current_modelview(current_mod);
}
LLRect get_whole_screen_region()
{
// <FS:Ansariel> Factor out calls to getInstance
LLViewerCamera& camera = LLViewerCamera::instance();
LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
// apply camera zoom transform (for high res screenshots)
F32 zoom_factor = camera.getZoomFactor(); // <FS:Ansariel> Factor out calls to getInstance
S16 sub_region = camera.getZoomSubRegion(); // <FS:Ansariel> Factor out calls to getInstance
if (zoom_factor > 1.f)
{
S32 num_horizontal_tiles = llceil(zoom_factor);
S32 tile_width = ll_round((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
S32 tile_height = ll_round((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
int tile_y = sub_region / num_horizontal_tiles;
int tile_x = sub_region - (tile_y * num_horizontal_tiles);
whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
}
return whole_screen;
}
bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
{
if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
{
F32 zoom_level = gAgentCamera.mHUDCurZoom;
LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
// <FS:Ansariel> Factor out calls to getInstance
//proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
//proj.element(2,2) = -0.01f;
F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
proj = gl_ortho(-0.5f * aspect_ratio, 0.5f * aspect_ratio, -0.5f, 0.5f, 0.f, hud_depth);
proj.element(2,2) = -0.01f;
// <//FS:Ansariel> Factor out calls to getInstance
glh::matrix4f mat;
F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
mat.set_translate(
glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
0.f));
proj *= mat;
glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
tmp_model *= mat;
model = tmp_model;
return true;
}
else
{
return false;
}
}
bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
{
LLRect whole_screen = get_whole_screen_region();
return get_hud_matrices(whole_screen, proj, model);
}
bool setup_hud_matrices()
{
LLRect whole_screen = get_whole_screen_region();
return setup_hud_matrices(whole_screen);
}
bool setup_hud_matrices(const LLRect& screen_region)
{
glh::matrix4f proj, model;
bool result = get_hud_matrices(screen_region, proj, model);
if (!result) return result;
// set up transform to keep HUD objects in front of camera
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.loadMatrix(proj.m);
set_current_projection(proj);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(model.m);
set_current_modelview(model);
return true;
}
void render_ui(F32 zoom_factor, int subfield)
{
LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_UI ); // render time capture - Primary UI stat can have HUD time overlap (TODO)
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
LL_PROFILE_GPU_ZONE("ui");
LLGLState::checkStates();
glh::matrix4f saved_view = get_current_modelview();
if (!gSnapshot)
{
gGL.pushMatrix();
gGL.loadMatrix(gGLLastModelView);
set_current_modelview(copy_matrix(gGLLastModelView));
}
if(LLSceneMonitor::getInstance()->needsUpdate())
{
gGL.pushMatrix();
gViewerWindow->setup2DRender();
LLSceneMonitor::getInstance()->compare();
gViewerWindow->setup3DRender();
gGL.popMatrix();
}
// apply gamma correction and post effects
gPipeline.renderFinalize();
{
LLGLState::checkStates();
LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD");
render_hud_elements();
// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay)
if (RlvActions::hasBehaviour(RLV_BHVR_SETOVERLAY))
{
LLVfxManager::instance().runEffect(EVisualEffect::RlvOverlay);
}
// [/RLVa:KB]
LLGLState::checkStates();
render_hud_attachments();
LLGLState::checkStates();
LLGLSDefault gls_default;
LLGLSUIDefault gls_ui;
{
gPipeline.disableLights();
}
bool render_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
if (render_ui)
{
if (!gDisconnected)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 3D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D);
LLGLState::checkStates();
render_ui_3d();
LLGLState::checkStates();
}
else
{
render_disconnected_background();
}
}
if (render_ui)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 2D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D);
LLHUDObject::renderAll();
render_ui_2d();
}
gViewerWindow->setup2DRender();
gViewerWindow->updateDebugText();
gViewerWindow->drawDebugText();
}
if (!gSnapshot)
{
set_current_modelview(saved_view);
gGL.popMatrix();
}
}
void swap()
{
LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Swap");
LL_PROFILE_GPU_ZONE("swap");
if (gDisplaySwapBuffers)
{
gViewerWindow->getWindow()->swapBuffers();
}
gDisplaySwapBuffers = true;
}
void renderCoordinateAxes()
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.begin(LLRender::LINES);
gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red
gGL.vertex3f(0.0f, 0.0f, 0.0f);
gGL.vertex3f(2.0f, 0.0f, 0.0f);
gGL.vertex3f(3.0f, 0.0f, 0.0f);
gGL.vertex3f(5.0f, 0.0f, 0.0f);
gGL.vertex3f(6.0f, 0.0f, 0.0f);
gGL.vertex3f(8.0f, 0.0f, 0.0f);
// Make an X
gGL.vertex3f(11.0f, 1.0f, 1.0f);
gGL.vertex3f(11.0f, -1.0f, -1.0f);
gGL.vertex3f(11.0f, 1.0f, -1.0f);
gGL.vertex3f(11.0f, -1.0f, 1.0f);
gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green
gGL.vertex3f(0.0f, 0.0f, 0.0f);
gGL.vertex3f(0.0f, 2.0f, 0.0f);
gGL.vertex3f(0.0f, 3.0f, 0.0f);
gGL.vertex3f(0.0f, 5.0f, 0.0f);
gGL.vertex3f(0.0f, 6.0f, 0.0f);
gGL.vertex3f(0.0f, 8.0f, 0.0f);
// Make a Y
gGL.vertex3f(1.0f, 11.0f, 1.0f);
gGL.vertex3f(0.0f, 11.0f, 0.0f);
gGL.vertex3f(-1.0f, 11.0f, 1.0f);
gGL.vertex3f(0.0f, 11.0f, 0.0f);
gGL.vertex3f(0.0f, 11.0f, 0.0f);
gGL.vertex3f(0.0f, 11.0f, -1.0f);
gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue
gGL.vertex3f(0.0f, 0.0f, 0.0f);
gGL.vertex3f(0.0f, 0.0f, 2.0f);
gGL.vertex3f(0.0f, 0.0f, 3.0f);
gGL.vertex3f(0.0f, 0.0f, 5.0f);
gGL.vertex3f(0.0f, 0.0f, 6.0f);
gGL.vertex3f(0.0f, 0.0f, 8.0f);
// Make a Z
gGL.vertex3f(-1.0f, 1.0f, 11.0f);
gGL.vertex3f(1.0f, 1.0f, 11.0f);
gGL.vertex3f(1.0f, 1.0f, 11.0f);
gGL.vertex3f(-1.0f, -1.0f, 11.0f);
gGL.vertex3f(-1.0f, -1.0f, 11.0f);
gGL.vertex3f(1.0f, -1.0f, 11.0f);
gGL.end();
}
void draw_axes()
{
LLGLSUIDefault gls_ui;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// A vertical white line at origin
LLVector3 v = gAgent.getPositionAgent();
gGL.begin(LLRender::LINES);
gGL.color3f(1.0f, 1.0f, 1.0f);
gGL.vertex3f(0.0f, 0.0f, 0.0f);
gGL.vertex3f(0.0f, 0.0f, 40.0f);
gGL.end();
// Some coordinate axes
gGL.pushMatrix();
gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
renderCoordinateAxes();
gGL.popMatrix();
}
void render_ui_3d()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
LLGLSPipeline gls_pipeline;
//////////////////////////////////////
//
// Render 3D UI elements
// NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
// so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
//
/////////////////////////////////////////////////////////////
//
// Render 2.5D elements (2D elements in the world)
// Stuff without z writes
//
// Debugging stuff goes before the UI.
stop_glerror();
gUIProgram.bind();
gGL.color4f(1, 1, 1, 1);
// Coordinate axes
// <FS:Ansariel> gSavedSettings replacement
//if (gSavedSettings.getBOOL("ShowAxes"))
static LLCachedControl<bool> showAxes(gSavedSettings, "ShowAxes");
if (showAxes)
// </FS:Ansariel>
{
draw_axes();
}
gViewerWindow->renderSelections(false, false, true); // Non HUD call in render_hud_elements
if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
// Render debugging beacons.
gObjectList.renderObjectBeacons();
gObjectList.resetObjectBeacons();
gSky.addSunMoonBeacons();
}
else
{
// Make sure particle effects disappear
LLHUDObject::renderAllForTimer();
}
stop_glerror();
}
void render_ui_2d()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
LLGLSUIDefault gls_ui;
/////////////////////////////////////////////////////////////
//
// Render 2D UI elements that overlay the world (no z compare)
// Disable wireframe mode below here, as this is HUD/menus
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Menu overlays, HUD, etc
gViewerWindow->setup2DRender();
// <FS:Ansariel> Factor out instance() call
//F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
//S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
LLViewerCamera& camera = LLViewerCamera::instance();
F32 zoom_factor = camera.getZoomFactor();
S16 sub_region = camera.getZoomSubRegion();
LLVector2& ui_scale_factor = LLUI::getScaleFactor();
if (zoom_factor > 1.f)
{
//decompose subregion number to x and y values
int pos_y = sub_region / llceil(zoom_factor);
int pos_x = sub_region - (pos_y*llceil(zoom_factor));
// offset for this tile
LLFontGL::sCurOrigin.mX -= ll_round((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
LLFontGL::sCurOrigin.mY -= ll_round((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
}
stop_glerror();
// render outline for HUD
if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
{
gUIProgram.bind();
gGL.pushMatrix();
S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
// <FS:Ansariel> Factor out instance() call
//gGL.scalef(LLUI::getScaleFactor().mV[0], LLUI::getScaleFactor().mV[1], 1.f);
gGL.scalef(ui_scale_factor.mV[0], ui_scale_factor.mV[1], 1.f);
gGL.translatef((F32)half_width, (F32)half_height, 0.f);
F32 zoom = gAgentCamera.mHUDCurZoom;
gGL.scalef(zoom,zoom,1.f);
gGL.color4fv(LLColor4::white.mV);
gl_rect_2d(-half_width, half_height, half_width, -half_height, false);
gGL.popMatrix();
gUIProgram.unbind();
stop_glerror();
}
if (LLPipeline::RenderUIBuffer)
{
if (LLView::sIsRectDirty)
{
LLView::sIsRectDirty = false;
LLRect t_rect;
gPipeline.mUIScreen.bindTarget();
gGL.setColorMask(true, true);
{
static const S32 pad = 8;
LLView::sDirtyRect.mLeft -= pad;
LLView::sDirtyRect.mRight += pad;
LLView::sDirtyRect.mBottom -= pad;
LLView::sDirtyRect.mTop += pad;
LLGLEnable scissor(GL_SCISSOR_TEST);
static LLRect last_rect = LLView::sDirtyRect;
//union with last rect to avoid mouse poop
last_rect.unionWith(LLView::sDirtyRect);
t_rect = LLView::sDirtyRect;
LLView::sDirtyRect = last_rect;
last_rect = t_rect;
// <FS:Ansariel> Factor out instance() call
//last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::getScaleFactor().mV[0]);
//last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::getScaleFactor().mV[0]);
//last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::getScaleFactor().mV[1]);
//last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::getScaleFactor().mV[1]);
last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / ui_scale_factor.mV[0]);
last_rect.mRight = LLRect::tCoordType(last_rect.mRight / ui_scale_factor.mV[0]);
last_rect.mTop = LLRect::tCoordType(last_rect.mTop / ui_scale_factor.mV[1]);
last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / ui_scale_factor.mV[1]);
LLRect clip_rect(last_rect);
glClear(GL_COLOR_BUFFER_BIT);
gViewerWindow->draw();
}
gPipeline.mUIScreen.flush();
gGL.setColorMask(true, false);
LLView::sDirtyRect = t_rect;
}
LLGLDisable cull(GL_CULL_FACE);
LLGLDisable blend(GL_BLEND);
S32 width = gViewerWindow->getWindowWidthScaled();
S32 height = gViewerWindow->getWindowHeightScaled();
gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
gGL.begin(LLRender::TRIANGLE_STRIP);
gGL.color4f(1.f,1.f,1.f,1.f);
gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(0, 0);
gGL.texCoord2f((F32)width, 0.f); gGL.vertex2i(width, 0);
gGL.texCoord2f(0.f, (F32)height); gGL.vertex2i(0, height);
gGL.texCoord2f((F32)width, (F32)height); gGL.vertex2i(width, height);
gGL.end();
}
else
{
gViewerWindow->draw();
}
// reset current origin for font rendering, in case of tiling render
LLFontGL::sCurOrigin.set(0, 0);
}
void render_disconnected_background()
{
gUIProgram.bind();
gGL.color4f(1,1,1,1);
if (!gDisconnectedImagep && gDisconnected)
{
LL_INFOS() << "Loading last bitmap..." << LL_ENDL;
std::string temp_str;
temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + LLStartUp::getScreenLastFilename();
LLPointer<LLImagePNG> image_png = new LLImagePNG;
if( !image_png->load(temp_str) )
{
//LL_INFOS() << "Bitmap load failed" << LL_ENDL;
return;
}
LLPointer<LLImageRaw> raw = new LLImageRaw;
if (!image_png->decode(raw, 0.0f))
{
LL_INFOS() << "Bitmap decode failed" << LL_ENDL;
gDisconnectedImagep = NULL;
return;
}
U8 *rawp = raw->getData();
S32 npixels = (S32)image_png->getWidth()*(S32)image_png->getHeight();
for (S32 i = 0; i < npixels; i++)
{
S32 sum = 0;
sum = *rawp + *(rawp+1) + *(rawp+2);
sum /= 3;
*rawp = ((S32)sum*6 + *rawp)/7;
rawp++;
*rawp = ((S32)sum*6 + *rawp)/7;
rawp++;
*rawp = ((S32)sum*6 + *rawp)/7;
rawp++;
}
raw->expandToPowerOfTwo();
gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false );
gStartTexture = gDisconnectedImagep;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
// Make sure the progress view always fills the entire window.
S32 width = gViewerWindow->getWindowWidthScaled();
S32 height = gViewerWindow->getWindowHeightScaled();
if (gDisconnectedImagep)
{
LLGLSUIDefault gls_ui;
gViewerWindow->setup2DRender();
gGL.pushMatrix();
{
// scale ui to reflect UIScaleFactor
// this can't be done in setup2DRender because it requires a
// pushMatrix/popMatrix pair
const LLVector2& display_scale = gViewerWindow->getDisplayScale();
gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
gGL.getTexUnit(0)->bind(gDisconnectedImagep);
gGL.color4f(1.f, 1.f, 1.f, 1.f);
gl_rect_2d_simple_tex(width, height);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
gGL.popMatrix();
}
gGL.flush();
gUIProgram.unbind();
}
void display_cleanup()
{
gDisconnectedImagep = NULL;
}