Merge branch 'DRTVWR-563' of https://bitbucket.org/lindenlab/viewer
commit
c100236f39
|
|
@ -54,7 +54,6 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;
|
|||
U32 wpo2(U32 i);
|
||||
|
||||
|
||||
#if LL_DARWIN
|
||||
// texture memory accounting (for OS X)
|
||||
static LLMutex sTexMemMutex;
|
||||
static std::unordered_map<U32, U32> sTextureAllocs;
|
||||
|
|
@ -119,22 +118,6 @@ U64 LLImageGL::getTextureBytesAllocated()
|
|||
return sTextureBytes;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define alloc_tex_image(width, height, pixformat) (void) width; (void) height; (void) pixformat;
|
||||
#define free_tex_image(texName) (void) texName;
|
||||
#define free_tex_images(count, texNames) (void) count; (void) texNames;
|
||||
#define free_cur_tex_image()
|
||||
|
||||
// static
|
||||
U64 LLImageGL::getTextureBytesAllocated()
|
||||
{
|
||||
// UNIMPLEMENTED OUTSIDE OF OS X, DO NOT CALL
|
||||
llassert(false);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//statics
|
||||
|
||||
U32 LLImageGL::sUniqueCount = 0;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@ class LLImageGL : public LLRefCount
|
|||
friend class LLTexUnit;
|
||||
public:
|
||||
|
||||
// For OS X use only -- get an estimate of how many bytes have been allocated in vram for textures
|
||||
// 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
|
||||
// video memory usage based on testing in lagland against an NVIDIA GPU.
|
||||
static U64 getTextureBytesAllocated();
|
||||
|
||||
// These 2 functions replace glGenTextures() and glDeleteTextures()
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@
|
|||
#include "llthreadsafequeue.h"
|
||||
#include "stringize.h"
|
||||
#include "llframetimer.h"
|
||||
#include "commoncontrol.h" // TODO: Remove after testing
|
||||
#include "llsd.h" // TODO: Remove after testing
|
||||
|
||||
// System includes
|
||||
#include <commdlg.h>
|
||||
|
|
@ -414,9 +416,12 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
|||
HWND mWindowHandle = NULL;
|
||||
HDC mhDC = 0;
|
||||
|
||||
// best guess at available video memory in MB
|
||||
std::atomic<U32> mAvailableVRAM;
|
||||
|
||||
bool mTryUseDXGIAdapter; // TODO: Remove after testing
|
||||
IDXGIAdapter3* mDXGIAdapter = nullptr;
|
||||
bool mTryUseD3DDevice; // TODO: Remove after testing
|
||||
LPDIRECT3D9 mD3D = nullptr;
|
||||
LPDIRECT3DDEVICE9 mD3DDevice = nullptr;
|
||||
};
|
||||
|
|
@ -4675,6 +4680,14 @@ void LLWindowWin32::getWindowChrome( U32 &aChromeW, U32 &aChromeH )
|
|||
inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
|
||||
: ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
|
||||
{
|
||||
const LLSD skipDXGI{ LL::CommonControl::get("Global", "DisablePrimaryGraphicsMemoryAccounting") }; // TODO: Remove after testing
|
||||
LL_WARNS() << "DisablePrimaryGraphicsMemoryAccounting: " << skipDXGI << ", as boolean: " << skipDXGI.asBoolean() << LL_ENDL;
|
||||
mTryUseDXGIAdapter = !skipDXGI.asBoolean();
|
||||
LL_WARNS() << "mTryUseDXGIAdapter: " << mTryUseDXGIAdapter << LL_ENDL;
|
||||
const LLSD skipD3D{ LL::CommonControl::get("Global", "DisableSecondaryGraphicsMemoryAccounting") }; // TODO: Remove after testing
|
||||
LL_WARNS() << "DisableSecondaryGraphicsMemoryAccounting: " << skipD3D << ", as boolean: " << skipD3D.asBoolean() << LL_ENDL;
|
||||
mTryUseD3DDevice = !skipD3D.asBoolean();
|
||||
LL_WARNS() << "mTryUseD3DDevice: " << mTryUseD3DDevice << LL_ENDL;
|
||||
ThreadPool::start();
|
||||
}
|
||||
|
||||
|
|
@ -4724,10 +4737,77 @@ private:
|
|||
std::string mPrev;
|
||||
};
|
||||
|
||||
// Print hardware debug info about available graphics adapters in ordinal order
|
||||
void debugEnumerateGraphicsAdapters()
|
||||
{
|
||||
LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL;
|
||||
|
||||
IDXGIFactory1* factory;
|
||||
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory);
|
||||
if (FAILED(res) || !factory)
|
||||
{
|
||||
LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT graphics_adapter_index = 0;
|
||||
IDXGIAdapter3* dxgi_adapter;
|
||||
while (true)
|
||||
{
|
||||
res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast<IDXGIAdapter**>(&dxgi_adapter));
|
||||
if (FAILED(res))
|
||||
{
|
||||
if (graphics_adapter_index == 0)
|
||||
{
|
||||
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
dxgi_adapter->GetDesc(&desc);
|
||||
std::wstring description_w((wchar_t*)desc.Description);
|
||||
std::string description(description_w.begin(), description_w.end());
|
||||
LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", "
|
||||
<< "Description: " << description << ", "
|
||||
<< "DeviceId: " << desc.DeviceId << ", "
|
||||
<< "SubSysId: " << desc.SubSysId << ", "
|
||||
<< "AdapterLuid: " << desc.AdapterLuid.HighPart << "_" << desc.AdapterLuid.LowPart << ", "
|
||||
<< "DedicatedVideoMemory: " << desc.DedicatedVideoMemory / 1024 / 1024 << ", "
|
||||
<< "DedicatedSystemMemory: " << desc.DedicatedSystemMemory / 1024 / 1024 << ", "
|
||||
<< "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL;
|
||||
}
|
||||
|
||||
if (dxgi_adapter)
|
||||
{
|
||||
dxgi_adapter->Release();
|
||||
dxgi_adapter = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
graphics_adapter_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (factory)
|
||||
{
|
||||
factory->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::initDX()
|
||||
{
|
||||
if (mDXGIAdapter == NULL)
|
||||
if (mDXGIAdapter == NULL && mTryUseDXGIAdapter)
|
||||
{
|
||||
debugEnumerateGraphicsAdapters();
|
||||
|
||||
IDXGIFactory4* pFactory = nullptr;
|
||||
|
||||
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory);
|
||||
|
|
@ -4743,15 +4823,22 @@ void LLWindowWin32::LLWindowWin32Thread::initDX()
|
|||
{
|
||||
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "EnumAdapters success" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
pFactory->Release();
|
||||
if (pFactory)
|
||||
{
|
||||
pFactory->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::initD3D()
|
||||
{
|
||||
if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0)
|
||||
if (mDXGIAdapter == NULL && mD3DDevice == NULL && mTryUseD3DDevice && mWindowHandle != 0)
|
||||
{
|
||||
mD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
|
||||
|
|
@ -4761,7 +4848,16 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
|
|||
d3dpp.Windowed = TRUE;
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
|
||||
mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
|
||||
HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
|
||||
|
||||
if (FAILED(res))
|
||||
{
|
||||
LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4770,44 +4866,68 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
|
|||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (mDXGIAdapter != nullptr)
|
||||
{
|
||||
// NOTE: what lies below is hand wavy math based on compatibility testing and observation against a variety of hardware
|
||||
// It doesn't make sense, but please don't refactor it to make sense. -- davep
|
||||
|
||||
DXGI_QUERY_VIDEO_MEMORY_INFO info;
|
||||
mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info);
|
||||
|
||||
// try to use no more than the available reserve minus 10%
|
||||
U32 target = info.Budget / 1024 / 1024;
|
||||
#if 0 // debug 0 budget and 0 CU
|
||||
info.Budget = 0;
|
||||
info.CurrentUsage = 0;
|
||||
#endif
|
||||
|
||||
// EXPERIMENTAL
|
||||
// Trying to zero in on a good target usage, code here should be tuned against observed behavior
|
||||
// of various hardware.
|
||||
if (target > 4096) // if 4GB are installed, try to leave 2GB free
|
||||
U32 budget_mb = info.Budget / 1024 / 1024;
|
||||
U32 afr_mb = info.AvailableForReservation / 1024 / 1024;
|
||||
// correct for systems that misreport budget
|
||||
if (budget_mb == 0)
|
||||
{
|
||||
// fall back to available for reservation clamped between 512MB and 2GB
|
||||
budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048);
|
||||
}
|
||||
|
||||
U32 cu_mb = info.CurrentUsage / 1024 / 1024;
|
||||
|
||||
// get an estimated usage based on texture bytes allocated
|
||||
U32 eu_mb = LLImageGL::getTextureBytesAllocated() * 2 / 1024 / 1024;
|
||||
|
||||
if (cu_mb == 0)
|
||||
{ // current usage is sometimes unreliable on Intel GPUs, fall back to estimated usage
|
||||
cu_mb = llmax((U32)1, eu_mb);
|
||||
}
|
||||
F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb;
|
||||
|
||||
U32 target_mb = info.Budget / 1024 / 1024;
|
||||
|
||||
if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free
|
||||
{
|
||||
target -= 2048;
|
||||
target_mb -= 2048;
|
||||
}
|
||||
else // if less than 4GB are installed, try not to use more than half of it
|
||||
{
|
||||
target /= 2;
|
||||
target_mb /= 2;
|
||||
}
|
||||
|
||||
U32 used_vram = info.CurrentUsage / 1024 / 1024;
|
||||
|
||||
mAvailableVRAM = used_vram < target ? target - used_vram : 0;
|
||||
mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0;
|
||||
|
||||
LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024
|
||||
<< "\nBudget: " << info.Budget / 1024 / 1024
|
||||
<< "\nCR: " << info.CurrentReservation / 1024 / 1024
|
||||
<< "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL;
|
||||
<< "\nCU: " << info.CurrentUsage / 1024 / 1024
|
||||
<< "\nEU: " << eu_mb << llformat(" (%.2f)", eu_error)
|
||||
<< "\nTU: " << target_mb
|
||||
<< "\nAM: " << mAvailableVRAM << LL_ENDL;
|
||||
|
||||
mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info);
|
||||
/*mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info);
|
||||
LL_INFOS("Window") << "\nNon-Local\nAFR: " << info.AvailableForReservation / 1024 / 1024
|
||||
<< "\nBudget: " << info.Budget / 1024 / 1024
|
||||
<< "\nCR: " << info.CurrentReservation / 1024 / 1024
|
||||
<< "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL;
|
||||
<< "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL;*/
|
||||
}
|
||||
else if (mD3DDevice != NULL)
|
||||
{ // fallback to D3D9
|
||||
mAvailableVRAM = mD3DDevice->GetAvailableTextureMem() / 1024 / 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::run()
|
||||
|
|
@ -4824,6 +4944,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
|
|||
if (mWindowHandle != 0)
|
||||
{
|
||||
// lazily call initD3D inside this loop to catch when mWindowHandle has been set
|
||||
// *TODO: Shutdown if this fails when mWindowHandle exists
|
||||
initD3D();
|
||||
|
||||
MSG msg;
|
||||
|
|
|
|||
|
|
@ -5481,6 +5481,29 @@
|
|||
<key>Backup</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<!-- TODO: Remove settings keys DisablePrimaryGraphicsMemoryAccounting and DisableSecondaryGraphicsMemoryAccounting after testing, and code that references them -->
|
||||
<key>DisablePrimaryGraphicsMemoryAccounting</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable the first method used to detect GPU memory use</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableSecondaryGraphicsMemoryAccounting</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable the second method used to detect GPU memory use, used as a fallback when the first method fails</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableTextHyperlinkActions</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -462,6 +462,7 @@ void LLPipeline::connectRefreshCachedSettingsSafe(const std::string name)
|
|||
|
||||
void LLPipeline::init()
|
||||
{
|
||||
LL_WARNS() << "Begin pipeline initialization" << LL_ENDL; // TODO: Remove after testing
|
||||
refreshCachedSettings();
|
||||
|
||||
gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
|
||||
|
|
@ -490,6 +491,7 @@ void LLPipeline::init()
|
|||
mInitialized = true;
|
||||
|
||||
stop_glerror();
|
||||
LL_WARNS() << "No GL errors yet. Pipeline initialization will continue." << LL_ENDL; // TODO: Remove after testing
|
||||
|
||||
//create render pass pools
|
||||
getPool(LLDrawPool::POOL_ALPHA);
|
||||
|
|
@ -552,7 +554,9 @@ void LLPipeline::init()
|
|||
|
||||
// Enable features
|
||||
|
||||
LL_WARNS() << "Shader initialization start" << LL_ENDL; // TODO: Remove after testing
|
||||
LLViewerShaderMgr::instance()->setShaders();
|
||||
LL_WARNS() << "Shader initialization end" << LL_ENDL; // TODO: Remove after testing
|
||||
|
||||
stop_glerror();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue