diff options
Diffstat (limited to 'indra/llwindow')
| -rw-r--r-- | indra/llwindow/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llwindow/llopenglview-objc.mm | 8 | ||||
| -rw-r--r-- | indra/llwindow/llwindow.cpp | 10 | ||||
| -rw-r--r-- | indra/llwindow/llwindow.h | 13 | ||||
| -rw-r--r-- | indra/llwindow/llwindowheadless.h | 135 | ||||
| -rw-r--r-- | indra/llwindow/llwindowmacosx.cpp | 19 | ||||
| -rw-r--r-- | indra/llwindow/llwindowmacosx.h | 3 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 568 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.h | 8 | 
9 files changed, 552 insertions, 214 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index ca08e38f77..7b1430c67c 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -127,6 +127,8 @@ if (WINDOWS)    list(APPEND llwindow_LINK_LIBRARIES         comdlg32     # Common Dialogs for ChooseColor         ole32 +       dxgi +       d3d9         )  endif (WINDOWS) diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 7936245744..9d497691d8 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -141,7 +141,12 @@ attributedStringInfo getSegments(NSAttributedString *str)      CGLError the_err = CGLQueryRendererInfo (CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers);      if(0 == the_err)      { -        CGLDescribeRenderer (info, 0, kCGLRPTextureMemoryMegabytes, &vram_megabytes); +        // The name, uses, and other platform definitions of gGLManager.mVRAM suggest that this is supposed to be total vram in MB, +        // rather than, say, just the texture memory. The two exceptions are: +        // 1. LLAppViewer::getViewerInfo() puts the value in a field labeled "TEXTURE_MEMORY" +        // 2. For years, this present function used kCGLRPTextureMemoryMegabytes +        // Now we use kCGLRPVideoMemoryMegabytes to bring it in line with everything else (except thatone label). +        CGLDescribeRenderer (info, 0, kCGLRPVideoMemoryMegabytes, &vram_megabytes);          CGLDestroyRendererInfo (info);      }      else @@ -256,6 +261,7 @@ attributedStringInfo getSegments(NSAttributedString *str)  		NSOpenGLPFADepthSize, 24,  		NSOpenGLPFAAlphaSize, 8,  		NSOpenGLPFAColorSize, 24, +		NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,  		0      }; diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index f4678a70c5..9e281dfc99 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -117,7 +117,8 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags)  	  mSwapMethod(SWAP_METHOD_UNDEFINED),  	  mHideCursorPermanent(FALSE),  	  mFlags(flags), -	  mHighSurrogate(0) +	  mHighSurrogate(0), +	  mRefreshRate(0)  {  } @@ -406,7 +407,10 @@ LLWindow* LLWindowManager::createWindow(  	BOOL enable_vsync,  	BOOL use_gl,  	BOOL ignore_pixel_depth, -	U32 fsaa_samples) +	U32 fsaa_samples, +    U32 max_cores, +    U32 max_vram, +    F32 max_gl_version)  {  	LLWindow* new_window; @@ -423,7 +427,7 @@ LLWindow* LLWindowManager::createWindow(  #elif LL_WINDOWS  		new_window = new LLWindowWin32(callbacks,  			title, name, x, y, width, height, flags,  -			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); +			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version);  #elif LL_DARWIN  		new_window = new LLWindowMacOSX(callbacks,  			title, name, x, y, width, height, flags,  diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 0edf39f6ef..b1408d894f 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -162,7 +162,10 @@ public:  	virtual F32	getNativeAspectRatio() = 0;  	virtual F32 getPixelAspectRatio() = 0;  	virtual void setNativeAspectRatio(F32 aspect) = 0; -	 + +	// query VRAM usage +	virtual U32 getAvailableVRAMMegabytes() = 0; +  	virtual void beforeDialog() {};	// prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode)  	virtual void afterDialog() {};	// undo whatever was done in beforeDialog() @@ -196,6 +199,8 @@ public:      // windows only DirectInput8 for joysticks      virtual void* getDirectInput8() { return NULL; };      virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; }; + +    virtual S32 getRefreshRate() { return mRefreshRate; }  protected:  	LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags);  	virtual ~LLWindow(); @@ -229,6 +234,7 @@ protected:  	U16			mHighSurrogate;  	S32			mMinWindowWidth;  	S32			mMinWindowHeight; +    S32         mRefreshRate;   	// Handle a UTF-16 encoding unit received from keyboard.   	// Converting the series of UTF-16 encoding units to UTF-32 data, @@ -299,7 +305,10 @@ public:  		BOOL enable_vsync = FALSE,  		BOOL use_gl = TRUE,  		BOOL ignore_pixel_depth = FALSE, -		U32 fsaa_samples = 0); +		U32 fsaa_samples = 0, +        U32 max_cores = 0, +        U32 max_vram = 0, +        F32 max_gl_version = 4.6f);  	static BOOL destroyWindow(LLWindow* window);  	static BOOL isWindowValid(LLWindow *window);  }; diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 410da79623..2f2c0de5bd 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -32,72 +32,79 @@  class LLWindowHeadless : public LLWindow  {  public: -	/*virtual*/ void show() {}; -	/*virtual*/ void hide() {}; -	/*virtual*/ void close() {}; -	/*virtual*/ BOOL getVisible() {return FALSE;}; -	/*virtual*/ BOOL getMinimized() {return FALSE;}; -	/*virtual*/ BOOL getMaximized() {return FALSE;}; -	/*virtual*/ BOOL maximize() {return FALSE;}; -	/*virtual*/ void minimize() {}; -	/*virtual*/ void restore() {}; -	/*virtual*/ BOOL getFullscreen() {return FALSE;}; -	/*virtual*/ BOOL getPosition(LLCoordScreen *position) {return FALSE;}; -	/*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;}; -	/*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;}; -	/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; -	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; -	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; -	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; -    void* createSharedContext()  { return nullptr; } -    void makeContextCurrent(void*)  {} -    void destroySharedContext(void*)  {} -    /*virtual*/ void toggleVSync(bool enable_vsync) { } -    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; -    /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; +	/*virtual*/ void show() override {} +	/*virtual*/ void hide() override {} +	/*virtual*/ void close() override {} +	/*virtual*/ BOOL getVisible() override {return FALSE;} +	/*virtual*/ BOOL getMinimized() override {return FALSE;} +	/*virtual*/ BOOL getMaximized() override {return FALSE;} +	/*virtual*/ BOOL maximize() override {return FALSE;} +	/*virtual*/ void minimize() override {} +	/*virtual*/ void restore() override {} +	// TODO: LLWindow::getFullscreen() is (intentionally?) NOT virtual. +	// Apparently the coder of LLWindowHeadless didn't realize that. Is it a +	// mistake to shadow the base-class method with an LLWindowHeadless +	// override when called on the subclass, yet call the base-class method +	// when indirecting through a polymorphic pointer or reference? +	BOOL getFullscreen() {return FALSE;} +	/*virtual*/ BOOL getPosition(LLCoordScreen *position) override {return FALSE;} +	/*virtual*/ BOOL getSize(LLCoordScreen *size) override {return FALSE;} +	/*virtual*/ BOOL getSize(LLCoordWindow *size) override {return FALSE;} +	/*virtual*/ BOOL setPosition(LLCoordScreen position) override {return FALSE;} +	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) override {return FALSE;} +	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) override {return FALSE;} +	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override {return FALSE;} +    void* createSharedContext() override  { return nullptr; } +    void makeContextCurrent(void*) override  {} +    void destroySharedContext(void*) override  {} +    /*virtual*/ void toggleVSync(bool enable_vsync) override { } +    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) override {return FALSE;} +    /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) override {return FALSE;}  #if LL_WINDOWS -    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; } +    /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) override { return FALSE; }  #endif -	/*virtual*/ void showCursor() {}; -	/*virtual*/ void hideCursor() {}; -	/*virtual*/ void showCursorFromMouseMove() {}; -	/*virtual*/ void hideCursorUntilMouseMove() {}; -	/*virtual*/ BOOL isCursorHidden() {return FALSE;}; -	/*virtual*/ void updateCursor() {}; -	//virtual ECursorType getCursor() { return mCurrentCursor; }; -	/*virtual*/ void captureMouse() {}; -	/*virtual*/ void releaseMouse() {}; -	/*virtual*/ void setMouseClipping( BOOL b ) {}; -	/*virtual*/ BOOL isClipboardTextAvailable() {return FALSE; }; -	/*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) {return FALSE; }; -	/*virtual*/ BOOL copyTextToClipboard(const LLWString &src) {return FALSE; }; -	/*virtual*/ void flashIcon(F32 seconds) {}; -	/*virtual*/ F32 getGamma() {return 1.0f; }; -	/*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma -	/*virtual*/ void setFSAASamples(const U32 fsaa_samples) { } -	/*virtual*/ U32 getFSAASamples() { return 0; } -	/*virtual*/ BOOL restoreGamma() {return FALSE; };	// Restore original gamma table (before updating gamma) -	//virtual ESwapMethod getSwapMethod() { return mSwapMethod; } -	/*virtual*/ void gatherInput() {}; -	/*virtual*/ void delayInputProcessing() {}; -	/*virtual*/ void swapBuffers(); +	/*virtual*/ void showCursor() override {} +	/*virtual*/ void hideCursor() override {} +	/*virtual*/ void showCursorFromMouseMove() override {} +	/*virtual*/ void hideCursorUntilMouseMove() override {} +	/*virtual*/ BOOL isCursorHidden() override {return FALSE;} +	/*virtual*/ void updateCursor() override {} +	//virtual ECursorType getCursor() override { return mCurrentCursor; } +	/*virtual*/ void captureMouse() override {} +	/*virtual*/ void releaseMouse() override {} +	/*virtual*/ void setMouseClipping( BOOL b ) override {} +	/*virtual*/ BOOL isClipboardTextAvailable() override {return FALSE; } +	/*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) override {return FALSE; } +	/*virtual*/ BOOL copyTextToClipboard(const LLWString &src) override {return FALSE; } +	/*virtual*/ void flashIcon(F32 seconds) override {} +	/*virtual*/ F32 getGamma() override {return 1.0f; } +	/*virtual*/ BOOL setGamma(const F32 gamma) override {return FALSE; } // Set the gamma +	/*virtual*/ void setFSAASamples(const U32 fsaa_samples) override { } +	/*virtual*/ U32 getFSAASamples() override { return 0; } +	/*virtual*/ BOOL restoreGamma() override {return FALSE; }	// Restore original gamma table (before updating gamma) +	//virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } +	/*virtual*/ void gatherInput() override {} +	/*virtual*/ void delayInputProcessing() override {} +	/*virtual*/ void swapBuffers() override;      // handy coordinate space conversion routines -	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) { return FALSE; }; -	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) { return FALSE; }; -	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) { return FALSE; }; -	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) { return FALSE; }; -	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) { return FALSE; }; -	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) { return FALSE; }; +	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return FALSE; } +	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return FALSE; } +	/*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override { return FALSE; } +	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override { return FALSE; } +	/*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override { return FALSE; } +	/*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override { return FALSE; } -	/*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; -	/*virtual*/ F32	getNativeAspectRatio() { return 1.0f; }; -	/*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; -	/*virtual*/ void setNativeAspectRatio(F32 ratio) {} +	/*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; } +	/*virtual*/ F32	getNativeAspectRatio() override { return 1.0f; } +	/*virtual*/ F32 getPixelAspectRatio() override { return 1.0f; } +	/*virtual*/ void setNativeAspectRatio(F32 ratio) override {} -	/*virtual*/ void *getPlatformWindow() { return 0; }; -	/*virtual*/ void bringToFront() {}; +    U32 getAvailableVRAMMegabytes() override { return 4096; } + +	/*virtual*/ void *getPlatformWindow() override { return 0; } +	/*virtual*/ void bringToFront() override {}  	LLWindowHeadless(LLWindowCallbacks* callbacks,  		const std::string& title, const std::string& name, @@ -113,12 +120,12 @@ private:  class LLSplashScreenHeadless : public LLSplashScreen  {  public: -	LLSplashScreenHeadless() {}; -	virtual ~LLSplashScreenHeadless() {}; +	LLSplashScreenHeadless() {} +	virtual ~LLSplashScreenHeadless() {} -	/*virtual*/ void showImpl() {}; -	/*virtual*/ void updateImpl(const std::string& mesg) {}; -	/*virtual*/ void hideImpl() {}; +	/*virtual*/ void showImpl() override {} +	/*virtual*/ void updateImpl(const std::string& mesg) override {} +	/*virtual*/ void hideImpl() override {}  }; diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index a0fc91399b..8bfaeca614 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -49,6 +49,8 @@ BOOL gHiDPISupport = TRUE;  const S32	BITS_PER_PIXEL = 32;  const S32	MAX_NUM_RESOLUTIONS = 32; +const S32   DEFAULT_REFRESH_RATE = 60; +  namespace  {      NSKeyEventRef mRawKeyEvent = NULL; @@ -654,6 +656,13 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits  		}  	} +    mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); +    if(mRefreshRate == 0) +    { +        //consider adding more appropriate fallback later +        mRefreshRate = DEFAULT_REFRESH_RATE; +    } +  	// Disable vertical sync for swap      toggleVSync(enable_vsync); @@ -1216,6 +1225,16 @@ F32 LLWindowMacOSX::getPixelAspectRatio()  	return 1.f;  } +U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { +    // MTL (and MoltenVK) has some additional gpu data, such as recommendedMaxWorkingSetSize and currentAllocatedSize. +    // But these are not available for OpenGL and/or our current mimimum OS version. +    // So we will estimate. +    static const U32 mb = 1024*1024; +    // We're asked for total available gpu memory, but we only have allocation info on texture usage. So estimate by doubling that. +    static const U32 total_factor = 2; // estimated total/textures +    return gGLManager.mVRAM - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); +} +  //static SInt32 oldWindowLevel;  // MBW -- XXX -- There's got to be a better way than this.  Find it, please... diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 851c860017..7614167213 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -100,6 +100,9 @@ public:  	F32 getPixelAspectRatio() override;  	void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } +	// query VRAM usage +    /*virtual*/ U32 getAvailableVRAMMegabytes() override; +  	void beforeDialog() override;  	void afterDialog() override; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6f67b131d1..43bef5ff68 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -47,6 +47,7 @@  #include "llglslshader.h"  #include "llthreadsafequeue.h"  #include "stringize.h" +#include "llframetimer.h"  // System includes  #include <commdlg.h> @@ -61,6 +62,10 @@  #include <sstream>  #include <utility>                  // std::pair +#include <d3d9.h> +#include <dxgi1_4.h> +#include <timeapi.h> +  // Require DirectInput version 8  #define DIRECTINPUT_VERSION 0x0800 @@ -347,6 +352,20 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool      void run() override; +    // initialzie DXGI adapter (for querying available VRAM) +    void initDX(); +     +    // initialize D3D (if DXGI cannot be used) +    void initD3D(); + +    // call periodically to update available VRAM +    void updateVRAMUsage(); + +    U32 getAvailableVRAMMegabytes() +    { +        return mAvailableVRAM; +    } +      /// called by main thread to post work to this window thread      template <typename CALLABLE>      void post(CALLABLE&& func) @@ -395,6 +414,15 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool      void gatherInput();      HWND mWindowHandle = NULL;      HDC mhDC = 0; + +    // best guess at available video memory in MB +    std::atomic<U32> mAvailableVRAM; + +    U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) + +    IDXGIAdapter3* mDXGIAdapter = nullptr; +    LPDIRECT3D9 mD3D = nullptr; +    LPDIRECT3DDEVICE9 mD3DDevice = nullptr;  }; @@ -404,13 +432,93 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,  							 BOOL fullscreen, BOOL clearBg,  							 BOOL enable_vsync, BOOL use_gl,  							 BOOL ignore_pixel_depth, -							 U32 fsaa_samples) -	: LLWindow(callbacks, fullscreen, flags) +							 U32 fsaa_samples, +                             U32 max_cores, +                             U32 max_vram, +                             F32 max_gl_version) +	:  +    LLWindow(callbacks, fullscreen, flags),  +    mMaxGLVersion(max_gl_version),  +    mMaxCores(max_cores)  {      sMainThreadId = LLThread::currentID();      mWindowThread = new LLWindowWin32Thread(); +    mWindowThread->mMaxVRAM = max_vram; +  	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways   	LoadLibrary(L"opengl32.dll"); +     +     +    if (mMaxCores != 0) +    { +        HANDLE hProcess = GetCurrentProcess(); +        mMaxCores = llmin(mMaxCores, (U32) 64); +        DWORD_PTR mask = 0; + +        for (int i = 0; i < mMaxCores; ++i) +        { +            mask |= ((DWORD_PTR) 1) << i; +        } + +        SetProcessAffinityMask(hProcess, mask); +    } + +#if 0 // this is probably a bad idea, but keep it in your back pocket if you see what looks like +        // process deprioritization during profiles +    // force high thread priority +    HANDLE hProcess = GetCurrentProcess(); + +    if (hProcess) +    { +        int priority = GetPriorityClass(hProcess); +        if (priority < REALTIME_PRIORITY_CLASS) +        { +            if (SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS)) +            { +                LL_INFOS() << "Set process priority to REALTIME_PRIORITY_CLASS" << LL_ENDL; +            } +            else +            { +                LL_INFOS() << "Failed to set process priority: " << std::hex << GetLastError() << LL_ENDL; +            } +        } +    } +#endif + +#if 0  // this is also probably a bad idea, but keep it in your back pocket for getting main thread off of background thread cores (see also LLThread::threadRun) +    HANDLE hThread = GetCurrentThread(); + +    SYSTEM_INFO sysInfo; + +    GetSystemInfo(&sysInfo); +    U32 core_count = sysInfo.dwNumberOfProcessors; + +    if (max_cores != 0) +    { +        core_count = llmin(core_count, max_cores); +    } + +    if (hThread) +    { +        int priority = GetThreadPriority(hThread); + +        if (priority < THREAD_PRIORITY_TIME_CRITICAL) +        { +            if (SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) +            { +                LL_INFOS() << "Set thread priority to THREAD_PRIORITY_TIME_CRITICAL" << LL_ENDL; +            } +            else +            { +                LL_INFOS() << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL; +            } + +            // tell main thread to prefer core 0 +            SetThreadIdealProcessor(hThread, 0); +        } +    } +#endif +  	mFSAASamples = fsaa_samples;  	mIconResource = gIconResource; @@ -583,7 +691,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,  	{  		current_refresh = 60;  	} - +    mRefreshRate = current_refresh;  	//-----------------------------------------------------------------------  	// Drop resolution and go fullscreen  	// use a display mode with our desired size and depth, with a refresh @@ -943,16 +1051,19 @@ BOOL LLWindowWin32::maximize()  	BOOL success = FALSE;  	if (!mWindowHandle) return success; -	WINDOWPLACEMENT placement; -	placement.length = sizeof(WINDOWPLACEMENT); - -	success = GetWindowPlacement(mWindowHandle, &placement); -	if (!success) return success; +    mWindowThread->post([=] +        { +            WINDOWPLACEMENT placement; +            placement.length = sizeof(WINDOWPLACEMENT); -	placement.showCmd = SW_MAXIMIZE; +            if (GetWindowPlacement(mWindowHandle, &placement)) +            { +                placement.showCmd = SW_MAXIMIZE; +                SetWindowPlacement(mWindowHandle, &placement); +            } +        }); -	success = SetWindowPlacement(mWindowHandle, &placement); -	return success; +    return TRUE;  }  BOOL LLWindowWin32::getFullscreen() @@ -1061,6 +1172,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO      {          current_refresh = 60;      } +    mRefreshRate = current_refresh;      gGLManager.shutdownGL();      //destroy gl context @@ -1292,22 +1404,6 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO  	LL_INFOS("Window") << "pfd.dwDamageMask:     " << pfd.dwDamageMask << LL_ENDL ;  	LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; -	if (pfd.cColorBits < 32) -	{ -		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), -			mCallbacks->translateString("MBError"), OSMB_OK); -        close(); -		return FALSE; -	} - -	if (pfd.cAlphaBits < 8) -	{ -		OSMessageBox(mCallbacks->translateString("MBAlpha"), -			mCallbacks->translateString("MBError"), OSMB_OK); -        close(); -		return FALSE; -	} -  	if (!SetPixelFormat(mhDC, pixel_format, &pfd))  	{  		OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), @@ -1347,8 +1443,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO  		attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;  		attrib_list[cur_attrib++] = 24; -		attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; -		attrib_list[cur_attrib++] = 8; +		//attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) +		//attrib_list[cur_attrib++] = 8;  		attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;  		attrib_list[cur_attrib++] = GL_TRUE; @@ -1366,7 +1462,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO  		attrib_list[cur_attrib++] = 24;  		attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; -		attrib_list[cur_attrib++] = 8; +		attrib_list[cur_attrib++] = 0;  		U32 end_attrib = 0;  		if (mFSAASamples > 0) @@ -1589,21 +1685,6 @@ const	S32   max_format  = (S32)num_formats - 1;  		<< " Depth Bits " << S32(pfd.cDepthBits)   		<< LL_ENDL; -	// make sure we have 32 bits per pixel -	if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32) -	{ -		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK); -		close(); -		return FALSE; -	} - -	if (pfd.cAlphaBits < 8) -	{ -		OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK); -		close(); -		return FALSE; -	} -  	mhRC = 0;  	if (wglCreateContextAttribsARB)  	{ //attempt to create a specific versioned context @@ -1621,8 +1702,6 @@ const	S32   max_format  = (S32)num_formats - 1;  		return FALSE;  	} -	LL_PROFILER_GPU_CONTEXT -  	if (!gGLManager.initGL())  	{  		OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); @@ -1654,6 +1733,8 @@ const	S32   max_format  = (S32)num_formats - 1;  		swapBuffers();  	} +    LL_PROFILER_GPU_CONTEXT; +  	return TRUE;  } @@ -1766,10 +1847,15 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw  void* LLWindowWin32::createSharedContext()  { +    mMaxGLVersion = llclamp(mMaxGLVersion, 3.f, 4.6f); + +    S32 version_major = llfloor(mMaxGLVersion); +    S32 version_minor = llround((mMaxGLVersion-version_major)*10); +      S32 attribs[] =      { -        WGL_CONTEXT_MAJOR_VERSION_ARB, 4, -        WGL_CONTEXT_MINOR_VERSION_ARB, 6, +        WGL_CONTEXT_MAJOR_VERSION_ARB, version_major, +        WGL_CONTEXT_MINOR_VERSION_ARB, version_minor,          WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,          WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,          0 @@ -1818,6 +1904,7 @@ void* LLWindowWin32::createSharedContext()  void LLWindowWin32::makeContextCurrent(void* contextPtr)  {      wglMakeCurrent(mhDC, (HGLRC) contextPtr); +    LL_PROFILER_GPU_CONTEXT;  }  void LLWindowWin32::destroySharedContext(void* contextPtr) @@ -2221,8 +2308,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_      LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); -    bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window"); -      if (NULL != window_imp)      {          // Juggle to make sure we can get negative positions for when @@ -2249,11 +2334,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_DEVICECHANGE:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); -            if (debug_window_proc) -            { -                LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param -                    << "; lParam=" << l_param << LL_ENDL; -            } +            LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param +                << "; lParam=" << l_param << LL_ENDL;              if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)              {                  WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); @@ -2317,14 +2399,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_                      BOOL activating = (BOOL)w_param;                      BOOL minimized = window_imp->getMinimized(); -                    if (debug_window_proc) -                    { -                        LL_INFOS("Window") << "WINDOWPROC ActivateApp " -                            << " activating " << S32(activating) -                            << " minimized " << S32(minimized) -                            << " fullscreen " << S32(window_imp->mFullscreen) -                            << LL_ENDL; -                    } +                    LL_INFOS("Window") << "WINDOWPROC ActivateApp " +                        << " activating " << S32(activating) +                        << " minimized " << S32(minimized) +                        << " fullscreen " << S32(window_imp->mFullscreen) +                        << LL_ENDL;                      if (window_imp->mFullscreen)                      { @@ -2369,13 +2448,10 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_                      // JC - I'm not sure why, but if we don't report that we handled the                       // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work                       // properly when we run fullscreen. -                    if (debug_window_proc) -                    { -                        LL_INFOS("Window") << "WINDOWPROC Activate " -                            << " activating " << S32(activating) -                            << " minimized " << S32(minimized) -                            << LL_ENDL; -                    } +                    LL_INFOS("Window") << "WINDOWPROC Activate " +                        << " activating " << S32(activating) +                        << " minimized " << S32(minimized) +                        << LL_ENDL;                  });              break; @@ -2454,12 +2530,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_                      window_imp->mRawLParam = l_param;                      { -                        if (debug_window_proc) -                        { -                            LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " -                                << " key " << S32(w_param) -                                << LL_ENDL; -                        } +                        LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " +                            << " key " << S32(w_param) +                            << LL_ENDL;                          gKeyboard->handleKeyDown(w_param, mask);                      } @@ -2484,12 +2557,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_                  {                      LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); -                    if (debug_window_proc) -                    { -                        LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " -                            << " key " << S32(w_param) -                            << LL_ENDL; -                    } +                    LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " +                        << " key " << S32(w_param) +                        << LL_ENDL;                      gKeyboard->handleKeyUp(w_param, mask);                  }              }); @@ -2499,10 +2569,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_IME_SETCONTEXT:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT"); -            if (debug_window_proc) -            { -                LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL; -            } +            LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;              if (LLWinImm::isAvailable() && window_imp->mPreeditor)              {                  l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; @@ -2513,10 +2580,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_IME_STARTCOMPOSITION:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION"); -            if (debug_window_proc) -            { -                LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL; -            } +            LL_INFOS("Window") << "WM_IME_STARTCOMPOSITION" << LL_ENDL;              if (LLWinImm::isAvailable() && window_imp->mPreeditor)              {                  WINDOW_IMP_POST(window_imp->handleStartCompositionMessage()); @@ -2527,10 +2591,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_IME_ENDCOMPOSITION:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION"); -            if (debug_window_proc) -            { -                LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL; -            } +            LL_INFOS("Window") << "WM_IME_ENDCOMPOSITION" << LL_ENDL;              if (LLWinImm::isAvailable() && window_imp->mPreeditor)              {                  return 0; @@ -2540,10 +2601,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_IME_COMPOSITION:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION"); -            if (debug_window_proc) -            { -                LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL; -            } +            LL_INFOS("Window") << "WM_IME_COMPOSITION" << LL_ENDL;              if (LLWinImm::isAvailable() && window_imp->mPreeditor)              {                  WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param)); @@ -2554,10 +2612,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_IME_REQUEST:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST"); -            if (debug_window_proc) -            { -                LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL; -            } +            LL_INFOS("Window") << "WM_IME_REQUEST" << LL_ENDL;              if (LLWinImm::isAvailable() && window_imp->mPreeditor)              {                  LRESULT result; @@ -2586,12 +2641,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_                      // it is worth trying.  The good old WM_CHAR works just fine even for supplementary                      // characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's                      // by ourselves.  It is not that tough.  -- Alissa Sabre @ SL -                    if (debug_window_proc) -                    { -                        LL_INFOS("Window") << "Debug WindowProc WM_CHAR " -                            << " key " << S32(w_param) -                            << LL_ENDL; -                    } +                    LL_INFOS("Window") << "Debug WindowProc WM_CHAR " +                        << " key " << S32(w_param) +                        << LL_ENDL;                      // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,                      // we *did* processed the event, so I believe we should not pass it to DefWindowProc...                      window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); @@ -2919,19 +2971,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_              S32 height = S32(HIWORD(l_param)); -            if (debug_window_proc) -            { -                BOOL maximized = (w_param == SIZE_MAXIMIZED); -                BOOL restored = (w_param == SIZE_RESTORED); -                BOOL minimized = (w_param == SIZE_MINIMIZED); - -                LL_INFOS("Window") << "WINDOWPROC Size " -                    << width << "x" << height -                    << " max " << S32(maximized) -                    << " min " << S32(minimized) -                    << " rest " << S32(restored) -                    << LL_ENDL; -            } +            LL_INFOS("Window"); +            BOOL maximized = (w_param == SIZE_MAXIMIZED); +            BOOL restored = (w_param == SIZE_RESTORED); +            BOOL minimized = (w_param == SIZE_MINIMIZED); + +            LL_CONT << "WINDOWPROC Size " +                << width << "x" << height +                << " max " << S32(maximized) +                << " min " << S32(minimized) +                << " rest " << S32(restored); +            LL_ENDL;              // There's an odd behavior with WM_SIZE that I would call a bug. If               // the window is maximized, and you call MoveWindow() with a size smaller @@ -2997,10 +3047,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_SETFOCUS:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS"); -            if (debug_window_proc) -            { -                LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; -            } +            LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;              WINDOW_IMP_POST(window_imp->mCallbacks->handleFocus(window_imp));              return 0;          } @@ -3008,10 +3055,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          case WM_KILLFOCUS:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS"); -            if (debug_window_proc) -            { -                LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; -            } +            LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;              WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp));              return 0;          } @@ -3132,10 +3176,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          default:          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default"); -            if (debug_window_proc) -            { -                LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL; -            } +            LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL;          }          break;          } @@ -3563,7 +3604,7 @@ BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re  	// Don't change anything if we don't have to  	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))  	{ -		if (dev_mode.dmPelsWidth        == width && +		if (dev_mode.dmPelsWidth        == width &&   			dev_mode.dmPelsHeight       == height &&  			dev_mode.dmBitsPerPel       == bits &&  			dev_mode.dmDisplayFrequency == refresh ) @@ -3629,12 +3670,15 @@ BOOL LLWindowWin32::resetDisplayResolution()  void LLWindowWin32::swapBuffers()  { -    LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; -    ASSERT_MAIN_THREAD(); -    glFlush(); //superstitious flush for maybe frame stall removal? -	SwapBuffers(mhDC); +    { +        LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; +        SwapBuffers(mhDC); +    } -    LL_PROFILER_GPU_COLLECT +    { +        LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("GPU Collect"); +        LL_PROFILER_GPU_COLLECT; +    }  } @@ -4585,13 +4629,17 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()  	return std::vector<std::string>();  } +U32 LLWindowWin32::getAvailableVRAMMegabytes() +{ +    return mWindowThread ? mWindowThread->getAvailableVRAMMegabytes() : 0; +}  #endif // LL_WINDOWS  inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() -    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) +    : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)  { -    ThreadPool::start(); +    LL::ThreadPool::start();  }  /** @@ -4640,17 +4688,226 @@ 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) +    { +        debugEnumerateGraphicsAdapters(); + +        IDXGIFactory4* pFactory = nullptr; + +        HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); + +        if (FAILED(res)) +        { +            LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; +        } +        else +        { +            res = pFactory->EnumAdapters(0, reinterpret_cast<IDXGIAdapter**>(&mDXGIAdapter)); +            if (FAILED(res)) +            { +                LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; +            } +            else +            { +                LL_INFOS() << "EnumAdapters success" << LL_ENDL; +            } +        } + +        if (pFactory) +        { +            pFactory->Release(); +        } +    } +} + +void LLWindowWin32::LLWindowWin32Thread::initD3D() +{ +    if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0) +    { +        mD3D = Direct3DCreate9(D3D_SDK_VERSION); +         +        D3DPRESENT_PARAMETERS d3dpp; + +        ZeroMemory(&d3dpp, sizeof(d3dpp)); +        d3dpp.Windowed = TRUE; +        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + +        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; +        } +    } +} + +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); +#if 0 // debug 0 budget and 0 CU +        info.Budget = 0; +        info.CurrentUsage = 0; +#endif + +        U32 budget_mb = info.Budget / 1024 / 1024; +        gGLManager.mVRAM = llmax(gGLManager.mVRAM, (S32) budget_mb); + +        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); +        } + +        if ( mMaxVRAM != 0) +        { +            budget_mb = llmin(budget_mb, mMaxVRAM); +        } + +        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); +        } +        U32 target_mb = budget_mb; + +        if (target_mb > 4096)  // if 4GB are installed, try to leave 2GB free  +        { +            target_mb -= 2048; +        } +        else // if less than 4GB are installed, try not to use more than half of it +        { +            target_mb /= 2; +        } + +        mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0; + +#if 0 +         +        F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb; +        LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024 +            << "\nBudget: " << info.Budget / 1024 / 1024 +            << "\nCR: " << info.CurrentReservation / 1024 / 1024 +            << "\nCU: " << info.CurrentUsage / 1024 / 1024 +            << "\nEU: " << eu_mb << llformat(" (%.2f)", eu_error) +            << "\nTU: " << target_mb +            << "\nAM: " << mAvailableVRAM << LL_ENDL; +#endif +    } +    else if (mD3DDevice != NULL) +    { // fallback to D3D9 +        mAvailableVRAM = mD3DDevice->GetAvailableTextureMem() / 1024 / 1024; +    } +} +  void LLWindowWin32::LLWindowWin32Thread::run()  {      sWindowThreadId = std::this_thread::get_id();      LogChange logger("Window"); +    initDX(); + +    //as good a place as any to up the MM timer resolution (see ms_sleep) +    //attempt to set timer resolution to 1ms +    TIMECAPS tc; +    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) +    { +        timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax)); +    } +      while (! getQueue().done())      {          LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;          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;              BOOL status;              if (mhDC == 0) @@ -4683,6 +4940,13 @@ void LLWindowWin32::LLWindowWin32Thread::run()              getQueue().runPending();          } +        // update available vram once every 3 seconds +        static LLFrameTimer vramTimer; +        if (vramTimer.getElapsedTimeF32() > 3.f) +        { +            updateVRAMUsage(); +            vramTimer.reset(); +        }  #if 0          {              LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); @@ -4691,6 +4955,26 @@ void LLWindowWin32::LLWindowWin32Thread::run()          }  #endif      } + +    //clean up DXGI/D3D resources +    if (mDXGIAdapter) +    { +        mDXGIAdapter->Release(); +        mDXGIAdapter = nullptr; +    } + +    if (mD3DDevice) +    { +        mD3DDevice->Release(); +        mD3DDevice = nullptr; +    } + +    if (mD3D) +    { +        mD3D->Release(); +        mD3D = nullptr; +    } +  }  void LLWindowWin32::post(const std::function<void()>& func) diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index b391acc12d..ff287a140e 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -108,7 +108,9 @@ public:  	/*virtual*/ F32 getPixelAspectRatio();  	/*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } -	/*virtual*/	BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); +    U32 getAvailableVRAMMegabytes() override; +	 +    /*virtual*/	BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b );  	/*virtual*/ void *getPlatformWindow();  	/*virtual*/ void bringToFront(); @@ -137,7 +139,7 @@ protected:  	LLWindowWin32(LLWindowCallbacks* callbacks,  		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,   		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, -		BOOL ignore_pixel_depth, U32 fsaa_samples); +		BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version);  	~LLWindowWin32();  	void	initCursors(); @@ -208,6 +210,8 @@ protected:  	F32			mCurrentGamma;  	U32			mFSAASamples; +    U32         mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit +    F32         mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6)  	WORD		mPrevGammaRamp[3][256];  	WORD		mCurrentGammaRamp[3][256];  	BOOL		mCustomGammaSet;  | 
