Torque3D/Engine/source/gfx/gfxInit.cpp
2017-05-28 16:51:31 -05:00

583 lines
18 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gfx/gfxInit.h"
#include "gfx/gfxTextureManager.h"
#include "gfx/gfxAPI.h"
#include "console/console.h"
#include "windowManager/platformWindowMgr.h"
#include "core/module.h"
Vector<GFXAdapter*> GFXInit::smAdapters( __FILE__, __LINE__ );
GFXInit::RegisterDeviceSignal* GFXInit::smRegisterDeviceSignal;
MODULE_BEGIN( GFX )
MODULE_INIT
{
GFXInit::init();
if( engineAPI::gUseConsoleInterop )
GFXDevice::initConsole();
GFXTextureManager::init();
}
MODULE_SHUTDOWN
{
GFXDevice::destroy();
GFXInit::cleanup();
}
MODULE_END;
IMPLEMENT_STATIC_CLASS( GFXInit, GFXAPI,
"Functions for tracking GFX adapters and initializing them into devices."
);
ConsoleDoc(
"@class GFXInit\n"
"@ingroup GFX\n"
"@brief Functions for tracking GFX adapters and initializing them into devices.\n"
);
inline static void _GFXInitReportAdapters(Vector<GFXAdapter*> &adapters)
{
for (U32 i = 0; i < adapters.size(); i++)
{
switch (adapters[i]->mType)
{
case OpenGL:
Con::printf(" OpenGL device found");
break;
case NullDevice:
Con::printf(" Null device found");
break;
case Direct3D11:
Con::printf(" Direct 3D (version 11.x) device found");
break;
default :
Con::printf(" Unknown device found");
break;
}
}
}
inline static void _GFXInitGetInitialRes(GFXVideoMode &vm, const Point2I &initialSize)
{
const U32 kDefaultWindowSizeX = 800;
const U32 kDefaultWindowSizeY = 600;
const bool kDefaultFullscreen = false;
const U32 kDefaultBitDepth = 32;
const U32 kDefaultRefreshRate = 60;
// cache the desktop size of the main screen
GFXVideoMode desktopVm = GFXInit::getDesktopResolution();
// load pref variables, properly choose windowed / fullscreen
const String resString = Con::getVariable("$pref::Video::mode");
// Set defaults into the video mode, then have it parse the user string.
vm.resolution.x = kDefaultWindowSizeX;
vm.resolution.y = kDefaultWindowSizeY;
vm.fullScreen = kDefaultFullscreen;
vm.bitDepth = kDefaultBitDepth;
vm.refreshRate = kDefaultRefreshRate;
vm.wideScreen = false;
vm.parseFromString(resString);
}
GFXInit::RegisterDeviceSignal& GFXInit::getRegisterDeviceSignal()
{
if (smRegisterDeviceSignal)
return *smRegisterDeviceSignal;
smRegisterDeviceSignal = new RegisterDeviceSignal();
return *smRegisterDeviceSignal;
}
void GFXInit::init()
{
// init only once.
static bool doneOnce = false;
if(doneOnce)
return;
doneOnce = true;
Con::printf( "GFX Init:" );
//find our adapters
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::enumerateAdapters();
GFXInit::getAdapters(&adapters);
if(!adapters.size())
Con::errorf("Could not find a display adapter");
//loop through and tell the user what kind of adapters we found
_GFXInitReportAdapters(adapters);
Con::printf( "" );
}
void GFXInit::cleanup()
{
while( smAdapters.size() )
{
GFXAdapter* adapter = smAdapters.last();
smAdapters.decrement();
delete adapter;
}
if( smRegisterDeviceSignal )
SAFE_DELETE( smRegisterDeviceSignal );
}
bool GFXInit::compareAdapterOutputDevice(const GFXAdapter* adapter, const char* outputDevice)
{
// If the adapter doesn't have an output display device, then it supports all of them
if(!adapter->mOutputName[0])
return true;
// Try and match the first part of the output device display name. For example,
// an adapter->mOutputName of "\\.\DISPLAY1" might correspond to a display name
// of "\\.\DISPLAY1\Monitor0". If two monitors are set up in duplicate mode then
// they will have the same 'display' part in their display name.
return (dStrstr(outputDevice, adapter->mOutputName) == outputDevice);
}
GFXAdapter* GFXInit::getAdapterOfType( GFXAdapterType type, const char* outputDevice )
{
bool testOutputDevice = false;
if(outputDevice && outputDevice[0])
testOutputDevice = true;
for( U32 i = 0; i < smAdapters.size(); i++ )
{
if( smAdapters[i]->mType == type )
{
if(testOutputDevice)
{
// Check if the output display device also matches
if(compareAdapterOutputDevice(smAdapters[i], outputDevice))
{
return smAdapters[i];
}
}
else
{
// No need to also test the output display device, so return
return smAdapters[i];
}
}
}
return NULL;
}
GFXAdapter* GFXInit::getAdapterOfType(GFXAdapterType type, S32 outputDeviceIndex)
{
for (U32 i = 0; i < smAdapters.size(); i++)
{
if (smAdapters[i]->mType == type)
{
if (smAdapters[i]->mIndex == outputDeviceIndex)
{
return smAdapters[i];
}
}
}
return NULL;
}
GFXAdapter* GFXInit::chooseAdapter( GFXAdapterType type, const char* outputDevice)
{
GFXAdapter* adapter = GFXInit::getAdapterOfType(type, outputDevice);
if(!adapter && type != OpenGL)
{
Con::errorf("The requested renderer, %s, doesn't seem to be available."
" Trying the default, OpenGL.", getAdapterNameFromType(type));
adapter = GFXInit::getAdapterOfType(OpenGL, outputDevice);
}
if(!adapter)
{
Con::errorf("The OpenGL renderer doesn't seem to be available. Trying the GFXNulDevice.");
adapter = GFXInit::getAdapterOfType(NullDevice, "");
}
AssertFatal( adapter, "There is no rendering device available whatsoever.");
return adapter;
}
GFXAdapter* GFXInit::chooseAdapter(GFXAdapterType type, S32 outputDeviceIndex)
{
GFXAdapter* adapter = GFXInit::getAdapterOfType(type, outputDeviceIndex);
if (!adapter && type != OpenGL)
{
Con::errorf("The requested renderer, %s, doesn't seem to be available."
" Trying the default, OpenGL.", getAdapterNameFromType(type));
adapter = GFXInit::getAdapterOfType(OpenGL, outputDeviceIndex);
}
if (!adapter)
{
Con::errorf("The OpenGL renderer doesn't seem to be available. Trying the GFXNulDevice.");
adapter = GFXInit::getAdapterOfType(NullDevice, 0);
}
AssertFatal(adapter, "There is no rendering device available whatsoever.");
return adapter;
}
const char* GFXInit::getAdapterNameFromType(GFXAdapterType type)
{
// must match GFXAdapterType order
static const char* _names[] = { "OpenGL", "D3D11", "NullDevice" };
if( type < 0 || type >= GFXAdapterType_Count )
{
Con::errorf( "GFXInit::getAdapterNameFromType - Invalid renderer type, defaulting to OpenGL" );
return _names[OpenGL];
}
return _names[type];
}
GFXAdapterType GFXInit::getAdapterTypeFromName(const char* name)
{
S32 ret = -1;
for(S32 i = 0; i < GFXAdapterType_Count; i++)
{
if( !dStricmp( getAdapterNameFromType((GFXAdapterType)i), name ) )
ret = i;
}
if( ret == -1 )
{
Con::errorf( "GFXInit::getAdapterTypeFromName - Invalid renderer name, defaulting to D3D11" );
ret = Direct3D11;
}
return (GFXAdapterType)ret;
}
GFXAdapter *GFXInit::getBestAdapterChoice()
{
// Get the user's preference for device...
const String renderer = Con::getVariable("$pref::Video::displayDevice");
const String outputDevice = Con::getVariable("$pref::Video::displayOutputDevice");
const String adapterDevice = Con::getVariable("$Video::forceDisplayAdapter");
GFXAdapterType adapterType = getAdapterTypeFromName(renderer.c_str());;
GFXAdapter *adapter = NULL;
if (adapterDevice.isEmpty())
{
adapter = chooseAdapter(adapterType, outputDevice.c_str());
}
else
{
S32 adapterIdx = dAtoi(adapterDevice.c_str());
if (adapterIdx == -1)
adapter = chooseAdapter(adapterType, outputDevice.c_str());
else
adapter = chooseAdapter(adapterType, adapterIdx);
}
// Did they have one? Return it.
if(adapter)
return adapter;
// Didn't have one. So make it up. Find the highest SM available. Prefer
// D3D to GL because if we have a D3D device at all we're on windows,
// and in an unknown situation on Windows D3D is probably the safest bet.
//
// If D3D is unavailable, we're not on windows, so GL is de facto the
// best choice!
F32 highestSMDX = 0.f, highestSMGL = 0.f;
GFXAdapter *foundAdapterGL = NULL, *foundAdapter11 = NULL;
for (S32 i = 0; i<smAdapters.size(); i++)
{
GFXAdapter *currAdapter = smAdapters[i];
switch (currAdapter->mType)
{
case Direct3D11:
if (currAdapter->mShaderModel > highestSMDX)
{
highestSMDX = currAdapter->mShaderModel;
foundAdapter11 = currAdapter;
}
break;
case OpenGL:
if (currAdapter->mShaderModel > highestSMGL)
{
highestSMGL = currAdapter->mShaderModel;
foundAdapterGL = currAdapter;
}
break;
default:
break;
}
}
// Return best found in order DX11, GL
if (foundAdapter11)
return foundAdapter11;
if (foundAdapterGL)
return foundAdapterGL;
// Uh oh - we didn't find anything. Grab whatever we can that's not Null...
for(S32 i=0; i<smAdapters.size(); i++)
if(smAdapters[i]->mType != NullDevice)
return smAdapters[i];
// Dare we return a null device? No. Just return NULL.
return NULL;
}
GFXVideoMode GFXInit::getInitialVideoMode()
{
GFXVideoMode vm;
_GFXInitGetInitialRes(vm, Point2I(800,600));
return vm;
}
S32 GFXInit::getAdapterCount()
{
return smAdapters.size();
}
void GFXInit::getAdapters(Vector<GFXAdapter*> *adapters)
{
adapters->clear();
for (U32 k = 0; k < smAdapters.size(); k++)
adapters->push_back(smAdapters[k]);
}
GFXVideoMode GFXInit::getDesktopResolution()
{
GFXVideoMode resVm;
// Retrieve Resolution Information.
resVm.bitDepth = WindowManager->getDesktopBitDepth();
resVm.resolution = WindowManager->getDesktopResolution();
resVm.fullScreen = false;
resVm.refreshRate = 60;
// Return results
return resVm;
}
void GFXInit::enumerateAdapters()
{
// Call each device class and have it report any adapters it supports.
if(smAdapters.size())
{
// CodeReview Seems like this is ok to just ignore? [bjg, 5/19/07]
//Con::warnf("GFXInit::enumerateAdapters - already have a populated adapter list, aborting re-analysis.");
return;
}
getRegisterDeviceSignal().trigger(GFXInit::smAdapters);
}
GFXDevice *GFXInit::createDevice( GFXAdapter *adapter )
{
Con::printf("Attempting to create GFX device: %s [%s]", adapter->getName(), adapter->getOutputName());
GFXDevice* temp = adapter->mCreateDeviceInstanceDelegate(adapter->mIndex);
if (temp)
{
Con::printf("Device created, setting adapter and enumerating modes");
temp->setAdapter(*adapter);
temp->enumerateVideoModes();
temp->getVideoModeList();
}
else
Con::errorf("Failed to create GFX device");
GFXDevice::getDeviceEventSignal().trigger(GFXDevice::deCreate);
return temp;
}
DefineEngineFunction( getDesktopResolution, Point3F, (),,
"Returns the width, height, and bitdepth of the screen/desktop.\n\n@ingroup GFX" )
{
GFXVideoMode res = GFXInit::getDesktopResolution();
return Point3F( res.resolution.x, res.resolution.y, res.bitDepth );
}
DefineEngineStaticMethod( GFXInit, getAdapterCount, S32, (),,
"Return the number of graphics adapters available. @ingroup GFX")
{
return GFXInit::getAdapterCount();
}
DefineEngineStaticMethod( GFXInit, getAdapterName, String, ( S32 index ),,
"Returns the name of the graphics adapter.\n"
"@param index The index of the adapter." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if(index >= 0 && index < adapters.size())
return adapters[index]->mName;
Con::errorf( "GFXInit::getAdapterName - Out of range adapter index." );
return String::EmptyString;
}
DefineEngineStaticMethod( GFXInit, getAdapterOutputName, String, ( S32 index ),,
"Returns the name of the graphics adapter's output display device.\n"
"@param index The index of the adapter." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if(index >= 0 && index < adapters.size())
return adapters[index]->mOutputName;
Con::errorf( "GFXInit::getAdapterOutputName - Out of range adapter index." );
return String::EmptyString;
}
DefineEngineStaticMethod( GFXInit, getAdapterType, GFXAdapterType, ( S32 index ),,
"Returns the type (D3D11, GL, Null) of a graphics adapter.\n"
"@param index The index of the adapter." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if( index >= 0 && index < adapters.size())
return adapters[index]->mType;
Con::errorf( "GFXInit::getAdapterType - Out of range adapter index." );
return GFXAdapterType_Count;
}
DefineEngineStaticMethod( GFXInit, getAdapterShaderModel, F32, ( S32 index ),,
"Returns the supported shader model of the graphics adapter or -1 if the index is bad.\n"
"@param index The index of the adapter." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if(index < 0 || index >= adapters.size())
{
Con::errorf("GFXInit::getAdapterShaderModel - Out of range adapter index.");
return -1.0f;
}
return adapters[index]->mShaderModel;
}
DefineEngineStaticMethod( GFXInit, getDefaultAdapterIndex, S32, (),,
"Returns the index of the default graphics adapter. This is the graphics device "
"which will be used to initialize the engine." )
{
GFXAdapter *a = GFXInit::getBestAdapterChoice();
// We have to find the index of the adapter in the list to
// return an index that makes sense to the script.
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
for(S32 i=0; i<adapters.size(); i++)
if ( adapters[i]->mIndex == a->mIndex &&
adapters[i]->mType == a->mType )
return i;
Con::warnf( "GFXInit::getDefaultAdapterIndex - Didn't find the adapter in the list!" );
return -1;
}
DefineEngineStaticMethod( GFXInit, getAdapterModeCount, S32, ( S32 index ),,
"Gets the number of modes available on the specified adapter.\n\n"
"@param index Index of the adapter to get modes from.\n"
"@return The number of video modes supported by the adapter or -1 if the given adapter was not found." )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if( index < 0 || index >= adapters.size())
{
Con::warnf( "GFXInit::getAdapterModeCount - The index was out of range." );
return -1;
}
return adapters[index]->mAvailableModes.size();
}
DefineConsoleStaticMethod( GFXInit, getAdapterMode, String, ( S32 index, S32 modeIndex ),,
"Gets the details of the specified adapter mode.\n\n"
"@param index Index of the adapter to query.\n"
"@param modeIndex Index of the mode to get data from.\n"
"@return A video mode string in the format 'width height fullscreen bitDepth refreshRate aaLevel'.\n"
"@see GuiCanvas::getVideoMode()" )
{
Vector<GFXAdapter*> adapters( __FILE__, __LINE__ );
GFXInit::getAdapters(&adapters);
if ( index < 0 || index >= adapters.size() )
{
Con::warnf( "GFXInit::getAdapterMode - The adapter index was out of range." );
return String::EmptyString;
}
if ( modeIndex < 0 || modeIndex >= adapters[index]->mAvailableModes.size() )
{
Con::warnf( "GFXInit::getAdapterMode - The mode index was out of range." );
return String::EmptyString;
}
const GFXVideoMode &vm = adapters[index]->mAvailableModes[modeIndex];
return vm.toString();
}
DefineEngineStaticMethod( GFXInit, createNullDevice, void, (),,
"Create the NULL graphics device used for testing or headless operation." )
{
// Enumerate things for GFX before we have an active device.
GFXInit::enumerateAdapters();
// Create a device.
GFXAdapter *a = GFXInit::chooseAdapter(NullDevice, "");
GFXDevice *newDevice = GFX;
// Do we have a global device already? (This is the site if you want
// to start rendering to multiple devices simultaneously)
if(newDevice == NULL)
newDevice = GFXInit::createDevice(a);
newDevice->setAllowRender( false );
}