diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index 0a028f95cc..ec12ab0404 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -10,6 +10,8 @@ // #include "PerformanceManager.h" +#include +#include #include #include "scripting/RenderScriptingInterface.h" @@ -65,6 +67,19 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP // Ugly case that prevent us to run deferred everywhere... bool isDeferredCapable = platform::Profiler::isRenderMethodDeferredCapable(); + auto masterDisplay = platform::getDisplay(platform::getMasterDisplay()); + + // eval recommanded PPI and Scale + float recommandedPpiScale = 1.0f; + const float RECOMMANDED_PPI[] = { 200.0f, 120.f, 160.f, 250.f}; + if (!masterDisplay.empty() && masterDisplay.count(platform::keys::display::ppi)) { + float ppi = masterDisplay[platform::keys::display::ppi]; + // only scale if the actual ppi is higher than the recommended ppi + if (ppi > RECOMMANDED_PPI[preset]) { + // make sure the scale is no less than a quarter + recommandedPpiScale = std::max(0.25f, RECOMMANDED_PPI[preset] / (float) ppi); + } + } switch (preset) { case PerformancePreset::HIGH: @@ -72,17 +87,21 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP RenderScriptingInterface::RenderMethod::DEFERRED : RenderScriptingInterface::RenderMethod::FORWARD ) ); + RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale); + RenderScriptingInterface::getInstance()->setShadowsEnabled(true); qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); DependencyManager::get()->setWorldDetailQuality(0.5f); - + break; case PerformancePreset::MID: RenderScriptingInterface::getInstance()->setRenderMethod((isDeferredCapable ? RenderScriptingInterface::RenderMethod::DEFERRED : RenderScriptingInterface::RenderMethod::FORWARD)); + RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale); + RenderScriptingInterface::getInstance()->setShadowsEnabled(false); qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::INTERACTIVE); DependencyManager::get()->setWorldDetailQuality(0.5f); @@ -93,6 +112,8 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP RenderScriptingInterface::getInstance()->setShadowsEnabled(false); qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::ECO); + RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale); + DependencyManager::get()->setWorldDetailQuality(0.75f); break; diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.cpp b/interface/src/scripting/PlatformInfoScriptingInterface.cpp index 84c4d923d0..cbd94b3dd5 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.cpp +++ b/interface/src/scripting/PlatformInfoScriptingInterface.cpp @@ -167,7 +167,9 @@ bool PlatformInfoScriptingInterface::isStandalone() { int PlatformInfoScriptingInterface::getNumCPUs() { return platform::getNumCPUs(); } - +int PlatformInfoScriptingInterface::getMasterCPU() { + return platform::getMasterCPU(); +} QString PlatformInfoScriptingInterface::getCPU(int index) { auto desc = platform::getCPU(index); return QString(desc.dump().c_str()); @@ -176,7 +178,9 @@ QString PlatformInfoScriptingInterface::getCPU(int index) { int PlatformInfoScriptingInterface::getNumGPUs() { return platform::getNumGPUs(); } - +int PlatformInfoScriptingInterface::getMasterGPU() { + return platform::getMasterGPU(); +} QString PlatformInfoScriptingInterface::getGPU(int index) { auto desc = platform::getGPU(index); return QString(desc.dump().c_str()); @@ -185,7 +189,9 @@ QString PlatformInfoScriptingInterface::getGPU(int index) { int PlatformInfoScriptingInterface::getNumDisplays() { return platform::getNumDisplays(); } - +int PlatformInfoScriptingInterface::getMasterDisplay() { + return platform::getMasterDisplay(); +} QString PlatformInfoScriptingInterface::getDisplay(int index) { auto desc = platform::getDisplay(index); return QString(desc.dump().c_str()); diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.h b/interface/src/scripting/PlatformInfoScriptingInterface.h index 113509d6d9..9ac67ec0bd 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.h +++ b/interface/src/scripting/PlatformInfoScriptingInterface.h @@ -94,8 +94,8 @@ public slots: * @returns {string} The graphics card type. * @deprecated This function is deprecated and will be removed. * use getNumGPUs() to know the number of GPUs in the hardware, at least one is expected - * use getGPU(0)["vendor"] to get the brand of the vendor - * use getGPU(0)["model"] to get the model name of the gpu + * use getGPU(getMasterGPU())["vendor"] to get the brand of the vendor + * use getGPU(getMasterGPU())["model"] to get the model name of the gpu */ QString getGraphicsCardType(); @@ -135,6 +135,13 @@ public slots: */ int getNumCPUs(); + /**jsdoc + * Get the index of the master CPU. + * @function PlatformInfo.getMasterCPU + * @returns {number} The index of the master CPU detected on the hardware platform. + */ + int getMasterCPU(); + /**jsdoc * Get the description of the CPU at the index parameter * expected fields are: @@ -152,6 +159,13 @@ public slots: */ int getNumGPUs(); + /**jsdoc + * Get the index of the master GPU. + * @function PlatformInfo.getMasterGPU + * @returns {number} The index of the master GPU detected on the hardware platform. + */ + int getMasterGPU(); + /**jsdoc * Get the description of the GPU at the index parameter * expected fields are: @@ -169,6 +183,13 @@ public slots: */ int getNumDisplays(); + /**jsdoc + * Get the index of the master Display. + * @function PlatformInfo.getMasterDisplay + * @returns {number} The index of the master Display detected on the hardware platform. + */ + int getMasterDisplay(); + /**jsdoc * Get the description of the Display at the index parameter * expected fields are: diff --git a/libraries/platform/src/platform/Platform.h b/libraries/platform/src/platform/Platform.h index 9405c77ae0..8cda6332ee 100644 --- a/libraries/platform/src/platform/Platform.h +++ b/libraries/platform/src/platform/Platform.h @@ -21,12 +21,15 @@ bool enumeratePlatform(); int getNumCPUs(); json getCPU(int index); +int getMasterCPU(); int getNumGPUs(); json getGPU(int index); +int getMasterGPU(); int getNumDisplays(); json getDisplay(int index); +int getMasterDisplay(); json getMemory(); diff --git a/libraries/platform/src/platform/PlatformKeys.h b/libraries/platform/src/platform/PlatformKeys.h index e6c255ce75..5008a4f6ce 100644 --- a/libraries/platform/src/platform/PlatformKeys.h +++ b/libraries/platform/src/platform/PlatformKeys.h @@ -20,6 +20,7 @@ namespace platform { namespace keys{ extern const char* model; extern const char* clockSpeed; extern const char* numCores; + extern const char* isMaster; } namespace gpu { extern const char* vendor; @@ -30,6 +31,8 @@ namespace platform { namespace keys{ extern const char* model; extern const char* videoMemory; extern const char* driver; + extern const char* displays; + extern const char* isMaster; } namespace nic { extern const char* mac; @@ -38,10 +41,19 @@ namespace platform { namespace keys{ namespace display { extern const char* description; extern const char* name; - extern const char* coordsLeft; - extern const char* coordsRight; - extern const char* coordsTop; - extern const char* coordsBottom; + extern const char* boundsLeft; + extern const char* boundsRight; + extern const char* boundsTop; + extern const char* boundsBottom; + extern const char* gpu; + extern const char* ppi; + extern const char* ppiDesktop; + extern const char* physicalWidth; + extern const char* physicalHeight; + extern const char* modeRefreshrate; + extern const char* modeWidth; + extern const char* modeHeight; + extern const char* isMaster; } namespace memory { extern const char* memTotal; diff --git a/libraries/platform/src/platform/Profiler.cpp b/libraries/platform/src/platform/Profiler.cpp index 1c055a5ec9..3e4dff9fd1 100644 --- a/libraries/platform/src/platform/Profiler.cpp +++ b/libraries/platform/src/platform/Profiler.cpp @@ -32,9 +32,9 @@ Profiler::Tier Profiler::profilePlatform() { return platformTier; } - // Not filtered yet, let s try to make sense of the cpu and gpu info - auto cpuInfo = platform::getCPU(0); - auto gpuInfo = platform::getGPU(0); + // Not filtered yet, let s try to make sense of the master cpu and master gpu info + auto cpuInfo = platform::getCPU(platform::getMasterCPU()); + auto gpuInfo = platform::getGPU(platform::getMasterGPU()); if (filterOnProcessors(computerInfo, cpuInfo, gpuInfo, platformTier)) { return platformTier; } @@ -133,10 +133,12 @@ bool filterOnProcessors(const platform::json& computer, const platform::json& cp // YES on macos EXCEPT for macbookair with gpu intel iris or intel HD 6000 bool Profiler::isRenderMethodDeferredCapable() { #if defined(Q_OS_MAC) + // Deferred works correctly on every supported macos platform at the moment, let s enable it +/* auto computer = platform::getComputer(); const auto computerModel = (computer.count(keys::computer::model) ? computer[keys::computer::model].get() : ""); - auto gpuInfo = platform::getGPU(0); + auto gpuInfo = platform::getGPU(getMasterGPU()); const auto gpuModel = (gpuInfo.count(keys::gpu::model) ? gpuInfo[keys::gpu::model].get() : ""); @@ -154,7 +156,7 @@ bool Profiler::isRenderMethodDeferredCapable() { if ((gpuModel.find("Intel ") != std::string::npos)) { return false; } - +*/ return true; #elif defined(Q_OS_ANDROID) return false; diff --git a/libraries/platform/src/platform/backend/AndroidPlatform.cpp b/libraries/platform/src/platform/backend/AndroidPlatform.cpp index b0a4c5e67b..4487d305cf 100644 --- a/libraries/platform/src/platform/backend/AndroidPlatform.cpp +++ b/libraries/platform/src/platform/backend/AndroidPlatform.cpp @@ -10,6 +10,7 @@ #include "../PlatformKeys.h" #include #include +#include using namespace platform; @@ -23,7 +24,7 @@ void AndroidInstance::enumerateCpus() { _cpus.push_back(cpu); } -void AndroidInstance::enumerateGpus() { +void AndroidInstance::enumerateGpusAndDisplays() { GPUIdent* ident = GPUIdent::getInstance(); json gpu = {}; gpu[keys::gpu::model] = ident->getName().toUtf8().constData(); diff --git a/libraries/platform/src/platform/backend/AndroidPlatform.h b/libraries/platform/src/platform/backend/AndroidPlatform.h index 6592b3519d..488f564057 100644 --- a/libraries/platform/src/platform/backend/AndroidPlatform.h +++ b/libraries/platform/src/platform/backend/AndroidPlatform.h @@ -16,7 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer() override; }; diff --git a/libraries/platform/src/platform/backend/LinuxPlatform.cpp b/libraries/platform/src/platform/backend/LinuxPlatform.cpp index 61501669cb..eb2c8d4259 100644 --- a/libraries/platform/src/platform/backend/LinuxPlatform.cpp +++ b/libraries/platform/src/platform/backend/LinuxPlatform.cpp @@ -12,6 +12,9 @@ #include #include #include + +#include + #include #include @@ -27,7 +30,7 @@ void LinuxInstance::enumerateCpus() { _cpus.push_back(cpu); } -void LinuxInstance::enumerateGpus() { +void LinuxInstance::enumerateGpusAndDisplays() { GPUIdent* ident = GPUIdent::getInstance(); json gpu = {}; gpu[keys::gpu::model] = ident->getName().toUtf8().constData(); diff --git a/libraries/platform/src/platform/backend/LinuxPlatform.h b/libraries/platform/src/platform/backend/LinuxPlatform.h index 2f2529db7c..0d2e567e0b 100644 --- a/libraries/platform/src/platform/backend/LinuxPlatform.h +++ b/libraries/platform/src/platform/backend/LinuxPlatform.h @@ -16,7 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer() override; }; diff --git a/libraries/platform/src/platform/backend/MACOSPlatform.cpp b/libraries/platform/src/platform/backend/MACOSPlatform.cpp index cacbd06816..66c9cd2c5d 100644 --- a/libraries/platform/src/platform/backend/MACOSPlatform.cpp +++ b/libraries/platform/src/platform/backend/MACOSPlatform.cpp @@ -12,16 +12,22 @@ #include #include #include -#include + +#include #ifdef Q_OS_MAC #include #include #include +#include +#include + #include #include #include +#include +#include #endif using namespace platform; @@ -36,73 +42,249 @@ void MACOSInstance::enumerateCpus() { _cpus.push_back(cpu); } -void MACOSInstance::enumerateGpus() { + +void MACOSInstance::enumerateGpusAndDisplays() { #ifdef Q_OS_MAC + // ennumerate the displays first + std::vector displayMasks; + { + uint32_t numDisplays = 0; + CGError error = CGGetOnlineDisplayList(0, nullptr, &numDisplays); + if (numDisplays <= 0 || error != kCGErrorSuccess) { + return; + } - GPUIdent* ident = GPUIdent::getInstance(); - json gpu = {}; + std::vector onlineDisplayIDs(numDisplays, 0); + error = CGGetOnlineDisplayList(onlineDisplayIDs.size(), onlineDisplayIDs.data(), &numDisplays); + if (error != kCGErrorSuccess) { + return; + } - gpu[keys::gpu::model] = ident->getName().toUtf8().constData(); - gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get()); - gpu[keys::gpu::videoMemory] = ident->getMemory(); - gpu[keys::gpu::driver] = ident->getDriver().toUtf8().constData(); - - _gpus.push_back(gpu); + for (auto displayID : onlineDisplayIDs) { + auto displaySize = CGDisplayScreenSize(displayID); + const auto MM_TO_IN = 0.0393701f; + auto displaySizeWidthInches = displaySize.width * MM_TO_IN; + auto displaySizeHeightInches = displaySize.height * MM_TO_IN; + + auto displayBounds = CGDisplayBounds(displayID); + auto displayMaster =CGDisplayIsMain(displayID); + + auto displayUnit =CGDisplayUnitNumber(displayID); + auto displayModel =CGDisplayModelNumber(displayID); + auto displayVendor = CGDisplayVendorNumber(displayID); + auto displaySerial = CGDisplaySerialNumber(displayID); + + auto displayMode = CGDisplayCopyDisplayMode(displayID); + auto displayModeWidth = CGDisplayModeGetPixelWidth(displayMode); + auto displayModeHeight = CGDisplayModeGetPixelHeight(displayMode); + auto displayRefreshrate = CGDisplayModeGetRefreshRate(displayMode); + + auto ppiH = displayModeWidth / displaySizeWidthInches; + auto ppiV = displayModeHeight / displaySizeHeightInches; + + auto ppiHScaled = displayBounds.size.width / displaySizeWidthInches; + auto ppiVScaled = displayBounds.size.height / displaySizeHeightInches; + + auto glmask = CGDisplayIDToOpenGLDisplayMask(displayID); + // Metal device ID is the recommended new way but requires objective c + // auto displayDevice = CGDirectDisplayCopyCurrentMetalDevice(displayID); + + CGDisplayModeRelease(displayMode); + + json display = {}; + + // Rect region of the desktop in desktop units + display[keys::display::boundsLeft] = displayBounds.origin.x; + display[keys::display::boundsRight] = displayBounds.origin.x + displayBounds.size.width; + display[keys::display::boundsTop] = displayBounds.origin.y; + display[keys::display::boundsBottom] = displayBounds.origin.y + displayBounds.size.height; + + // PPI & resolution + display[keys::display::physicalWidth] = displaySizeWidthInches; + display[keys::display::physicalHeight] = displaySizeHeightInches; + display[keys::display::modeWidth] = displayModeWidth; + display[keys::display::modeHeight] = displayModeHeight; + + //Average the ppiH and V for the simple ppi + display[keys::display::ppi] = std::round(0.5f * (ppiH + ppiV)); + display[keys::display::ppiDesktop] = std::round(0.5f * (ppiHScaled + ppiVScaled)); + + // refreshrate + display[keys::display::modeRefreshrate] = displayRefreshrate; + + // Master display ? + display[keys::display::isMaster] = (displayMaster ? true : false); + + // Macos specific + display["macos_unit"] = displayUnit; + display["macos_vendor"] = displayVendor; + display["macos_model"] = displayModel; + display["macos_serial"] = displaySerial; + display["macos_glmask"] = glmask; + displayMasks.push_back(glmask); + + _displays.push_back(display); + } + } -#endif + // Collect Renderer info as exposed by the CGL layers + GLuint cglDisplayMask = -1; // Iterate over all of them. + CGLRendererInfoObj rendererInfo; + GLint rendererInfoCount; + CGLError error = CGLQueryRendererInfo(cglDisplayMask, &rendererInfo, &rendererInfoCount); + if (rendererInfoCount <= 0 || 0 != error) { + return; + } + + // Iterate over all of the renderers and use the figure for the one with the most VRAM, + // on the assumption that this is the one that will actually be used. + for (GLint i = 0; i < rendererInfoCount; i++) { + struct CGLRendererDesc { + int rendererID{0}; + int deviceVRAM{0}; + int accelerated{0}; + int displayMask{0}; + } desc; + + CGLDescribeRenderer(rendererInfo, i, kCGLRPRendererID, &desc.rendererID); + CGLDescribeRenderer(rendererInfo, i, kCGLRPVideoMemoryMegabytes, &desc.deviceVRAM); + CGLDescribeRenderer(rendererInfo, i, kCGLRPDisplayMask, &desc.displayMask); + CGLDescribeRenderer(rendererInfo, i, kCGLRPAccelerated, &desc.accelerated); + + // If this renderer is not hw accelerated then just skip it in the enumeration + if (!desc.accelerated) { + continue; + } + + // From the rendererID identify the vendorID + // https://github.com/apitrace/apitrace/blob/master/retrace/glws_cocoa.mm + GLint vendorID = desc.rendererID & kCGLRendererIDMatchingMask & ~0xfff; + const GLint VENDOR_ID_SOFTWARE { 0x00020000 }; + const GLint VENDOR_ID_AMD { 0x00021000 }; + const GLint VENDOR_ID_NVIDIA { 0x00022000 }; + const GLint VENDOR_ID_INTEL { 0x00024000 }; + + const char* vendorName; + switch (vendorID) { + case VENDOR_ID_SOFTWARE: + // Software renderer then skip it (should already have been caught by hwaccelerated test abve + continue; + break; + case VENDOR_ID_AMD: + vendorName = keys::gpu::vendor_AMD; + break; + case VENDOR_ID_NVIDIA: + vendorName = keys::gpu::vendor_NVIDIA; + break; + case VENDOR_ID_INTEL: + vendorName = keys::gpu::vendor_Intel; + break; + default: + vendorName = keys::UNKNOWN; + break; + } + + //once we reach this point, the renderer is legit + // Start defining the gpu json + json gpu = {}; + gpu[keys::gpu::vendor] = vendorName; + gpu[keys::gpu::videoMemory] = desc.deviceVRAM; + gpu["macos_rendererID"] = desc.rendererID; + gpu["macos_displayMask"] = desc.displayMask; + + std::vector displayIndices; + for (int d = 0; d < (int) displayMasks.size(); d++) { + if (desc.displayMask & displayMasks[d]) { + displayIndices.push_back(d); + _displays[d][keys::display::gpu] = _gpus.size(); + } + } + gpu[keys::gpu::displays] = displayIndices; + + _gpus.push_back(gpu); + } + + CGLDestroyRendererInfo(rendererInfo); + + + { //get gpu information from the system profiler that we don't know how to retreive otherwise + struct ChipsetModelDesc { + std::string model; + std::string vendor; + int deviceID{0}; + int videoMemory{0}; + }; + std::vector chipsetDescs; + FILE* stream = popen("system_profiler SPDisplaysDataType | grep -e Chipset -e VRAM -e Vendor -e \"Device ID\"", "r"); + std::ostringstream hostStream; + while (!feof(stream) && !ferror(stream)) { + char buf[128]; + int bytesRead = fread(buf, 1, 128, stream); + hostStream.write(buf, bytesRead); + } + std::string gpuArrayDesc = hostStream.str(); + + // Find the Chipset model first + const std::regex chipsetModelToken("(Chipset Model: )(.*)"); + std::smatch found; + + while (std::regex_search(gpuArrayDesc, found, chipsetModelToken)) { + ChipsetModelDesc desc; -} - -void MACOSInstance::enumerateDisplays() { -#ifdef Q_OS_MAC - auto displayID = CGMainDisplayID(); - auto displaySize = CGDisplayScreenSize(displayID); - - const auto MM_TO_IN = 0.0393701; - auto displaySizeWidthInches = displaySize.width * MM_TO_IN; - auto displaySizeHeightInches = displaySize.height * MM_TO_IN; - auto displaySizeDiagonalInches = sqrt(displaySizeWidthInches * displaySizeWidthInches + displaySizeHeightInches * displaySizeHeightInches); + desc.model = found.str(2); + + // Find the end of the gpu block + gpuArrayDesc = found.suffix(); + std::string gpuDesc = gpuArrayDesc; + const std::regex endGpuToken("Chipset Model: "); + if (std::regex_search(gpuArrayDesc, found, endGpuToken)) { + gpuDesc = found.prefix(); + } + + // Find the vendor + desc.vendor = findGPUVendorInDescription(desc.model); + + // Find the memory amount in MB + const std::regex memoryToken("(VRAM .*: )(.*)"); + if (std::regex_search(gpuDesc, found, memoryToken)) { + auto memAmountUnit = found.str(2); + std::smatch amount; + const std::regex memAmountGBToken("(\\d*) GB"); + const std::regex memAmountMBToken("(\\d*) MB"); + const int GB_TO_MB { 1024 }; + if (std::regex_search(memAmountUnit, amount, memAmountGBToken)) { + desc.videoMemory = std::stoi(amount.str(1)) * GB_TO_MB; + } else if (std::regex_search(memAmountUnit, amount, memAmountMBToken)) { + desc.videoMemory = std::stoi(amount.str(1)); + } else { + desc.videoMemory = std::stoi(memAmountUnit); + } + } + + // Find the Device ID + const std::regex deviceIDToken("(Device ID: )(.*)"); + if (std::regex_search(gpuDesc, found, deviceIDToken)) { + desc.deviceID = std::stoi(found.str(2), 0, 16); + } + + chipsetDescs.push_back(desc); + } + + // GO through the detected gpus in order and complete missing information from ChipsetModelDescs + // assuming the order is the same and checking that the vendor and memory amount match as a simple check + auto numDescs = (int) std::min(chipsetDescs.size(),_gpus.size()); + for (int i = 0; i < numDescs; ++i) { + const auto& chipset = chipsetDescs[i]; + auto& gpu = _gpus[i]; + + if ( (chipset.vendor.find( gpu[keys::gpu::vendor]) != std::string::npos) + && (chipset.videoMemory == gpu[keys::gpu::videoMemory]) ) { + gpu[keys::gpu::model] = chipset.model; + gpu["macos_deviceID"] = chipset.deviceID; + } + } + } - auto displayBounds = CGDisplayBounds(displayID); - auto displayMaster =CGDisplayIsMain(displayID); - - auto displayUnit =CGDisplayUnitNumber(displayID); - auto displayModel =CGDisplayModelNumber(displayID); - auto displayVendor = CGDisplayVendorNumber(displayID); - auto displaySerial = CGDisplaySerialNumber(displayID); - - auto displayMode = CGDisplayCopyDisplayMode(displayID); - auto displayModeWidth = CGDisplayModeGetPixelWidth(displayMode); - auto displayModeHeight = CGDisplayModeGetPixelHeight(displayMode); - auto displayRefreshrate = CGDisplayModeGetRefreshRate(displayMode); - - CGDisplayModeRelease(displayMode); - - json display = {}; - - display["physicalWidth"] = displaySizeWidthInches; - display["physicalHeight"] = displaySizeHeightInches; - display["physicalDiagonal"] = displaySizeDiagonalInches; - - display["ppi"] = sqrt(displayModeHeight * displayModeHeight + displayModeWidth * displayModeWidth) / displaySizeDiagonalInches; - - display["coordLeft"] = displayBounds.origin.x; - display["coordRight"] = displayBounds.origin.x + displayBounds.size.width; - display["coordTop"] = displayBounds.origin.y; - display["coordBottom"] = displayBounds.origin.y + displayBounds.size.height; - - display["isMaster"] = displayMaster; - - display["unit"] = displayUnit; - display["vendor"] = displayVendor; - display["model"] = displayModel; - display["serial"] = displaySerial; - - display["refreshrate"] =displayRefreshrate; - display["modeWidth"] = displayModeWidth; - display["modeHeight"] = displayModeHeight; - - _displays.push_back(display); #endif } @@ -132,11 +314,11 @@ void MACOSInstance::enumerateComputer(){ _computer[keys::computer::model]=std::string(model); free(model); - -#endif auto sysInfo = QSysInfo(); _computer[keys::computer::OSVersion] = sysInfo.kernelVersion().toStdString(); +#endif + } diff --git a/libraries/platform/src/platform/backend/MACOSPlatform.h b/libraries/platform/src/platform/backend/MACOSPlatform.h index e893dda739..f249dad001 100644 --- a/libraries/platform/src/platform/backend/MACOSPlatform.h +++ b/libraries/platform/src/platform/backend/MACOSPlatform.h @@ -16,8 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; - void enumerateDisplays() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer() override; }; diff --git a/libraries/platform/src/platform/backend/Platform.cpp b/libraries/platform/src/platform/backend/Platform.cpp index 9284e0b3a0..17d9d8019e 100644 --- a/libraries/platform/src/platform/backend/Platform.cpp +++ b/libraries/platform/src/platform/backend/Platform.cpp @@ -21,7 +21,8 @@ namespace platform { namespace keys { const char* model = "model"; const char* clockSpeed = "clockSpeed"; const char* numCores = "numCores"; - } + const char* isMaster = "isMaster"; + } namespace gpu { const char* vendor = "vendor"; const char* vendor_NVIDIA = "NVIDIA"; @@ -31,6 +32,8 @@ namespace platform { namespace keys { const char* model = "model"; const char* videoMemory = "videoMemory"; const char* driver = "driver"; + const char* displays = "displays"; + const char* isMaster = "isMaster"; } namespace nic { const char* mac = "mac"; @@ -39,10 +42,19 @@ namespace platform { namespace keys { namespace display { const char* description = "description"; const char* name = "deviceName"; - const char* coordsLeft = "coordinatesleft"; - const char* coordsRight = "coordinatesright"; - const char* coordsTop = "coordinatestop"; - const char* coordsBottom = "coordinatesbottom"; + const char* boundsLeft = "boundsLeft"; + const char* boundsRight = "boundsRight"; + const char* boundsTop = "boundsTop"; + const char* boundsBottom = "boundsBottom"; + const char* gpu = "gpu"; + const char* ppi = "ppi"; + const char* ppiDesktop = "ppiDesktop"; + const char* physicalWidth = "physicalWidth"; + const char* physicalHeight = "physicalHeight"; + const char* modeRefreshrate = "modeRefreshrate"; + const char* modeWidth = "modeWidth"; + const char* modeHeight = "modeHeight"; + const char* isMaster = "isMaster"; } namespace memory { const char* memTotal = "memTotal"; @@ -117,6 +129,10 @@ json platform::getCPU(int index) { return _instance->getCPU(index); } +int platform::getMasterCPU() { + return _instance->getMasterCPU(); +} + int platform::getNumGPUs() { return _instance->getNumGPUs(); } @@ -125,6 +141,10 @@ json platform::getGPU(int index) { return _instance->getGPU(index); } +int platform::getMasterGPU() { + return _instance->getMasterGPU(); +} + int platform::getNumDisplays() { return _instance->getNumDisplays(); } @@ -133,6 +153,10 @@ json platform::getDisplay(int index) { return _instance->getDisplay(index); } +int platform::getMasterDisplay() { + return _instance->getMasterDisplay(); +} + json platform::getMemory() { return _instance->getMemory(); } diff --git a/libraries/platform/src/platform/backend/PlatformInstance.cpp b/libraries/platform/src/platform/backend/PlatformInstance.cpp index 33b19cd012..038521d398 100644 --- a/libraries/platform/src/platform/backend/PlatformInstance.cpp +++ b/libraries/platform/src/platform/backend/PlatformInstance.cpp @@ -16,18 +16,83 @@ using namespace platform; bool Instance::enumeratePlatform() { + //clear all knowledge + _computer.clear(); + _memory.clear(); + _cpus.clear(); + _gpus.clear(); + _displays.clear(); + _nics.clear(); + + // enumerate platform components enumerateComputer(); enumerateMemory(); enumerateCpus(); - enumerateGpus(); - enumerateDisplays(); + enumerateGpusAndDisplays(); enumerateNics(); + + // eval the master index for each platform scopes + updateMasterIndices(); // And profile the platform and put the tier in "computer" _computer[keys::computer::profileTier] = Profiler::TierNames[Profiler::profilePlatform()]; return true; } + +void Instance::updateMasterIndices() { + // We assume a single CPU at the moment: + { + if (!_cpus.empty()) { + _masterCPU = 0; + _cpus[0][keys::cpu::isMaster] = true; + } else { + _masterCPU = NOT_FOUND; + } + } + + // Go through the displays list + { + _masterDisplay = NOT_FOUND; + for (int i = 0; i < (int) _displays.size(); ++i) { + const auto& display = _displays[i]; + if (display.count(keys::display::isMaster)) { + if (display[keys::display::isMaster].get()) { + _masterDisplay = i; + break; + } + } + } + // NO master display found, return the first one or NOT_FOUND if no display + if (_masterDisplay == NOT_FOUND) { + if (!_displays.empty()) { + _masterDisplay = 0; + _displays[0][keys::display::isMaster] = true; + } + } + } + + // From the master display decide the master gpu + { + _masterGPU = NOT_FOUND; + if (_masterDisplay != NOT_FOUND) { + const auto& display = _displays[_masterDisplay]; + // FInd the GPU index of the master display + if (display.count(keys::display::gpu)) { + _masterGPU = display[keys::display::gpu]; + _gpus[_masterGPU][keys::gpu::isMaster] = true; + } + } + // NO master GPU found from master display, bummer, return the first one or NOT_FOUND if no display + if (_masterGPU == NOT_FOUND) { + if (!_gpus.empty()) { + _masterGPU = 0; + _gpus[0][keys::gpu::isMaster] = true; + } + } + } +} + void Instance::enumerateNics() { QNetworkInterface interface; foreach(interface, interface.allInterfaces()) { @@ -57,6 +122,7 @@ json Instance::getGPU(int index) { return _gpus.at(index); } + json Instance::getDisplay(int index) { assert(index <(int) _displays.size()); @@ -98,13 +164,13 @@ json Instance::listAllKeys() { keys::gpu::model, keys::gpu::videoMemory, keys::gpu::driver, + keys::gpu::displays, - keys::display::description, - keys::display::name, - keys::display::coordsLeft, - keys::display::coordsRight, - keys::display::coordsTop, - keys::display::coordsBottom, + keys::display::boundsLeft, + keys::display::boundsRight, + keys::display::boundsTop, + keys::display::boundsBottom, + keys::display::gpu, keys::memory::memTotal, diff --git a/libraries/platform/src/platform/backend/PlatformInstance.h b/libraries/platform/src/platform/backend/PlatformInstance.h index 6ceacaa3ff..069124853e 100644 --- a/libraries/platform/src/platform/backend/PlatformInstance.h +++ b/libraries/platform/src/platform/backend/PlatformInstance.h @@ -17,16 +17,21 @@ namespace platform { class Instance { public: + const int NOT_FOUND { -1 }; + bool virtual enumeratePlatform(); int getNumCPUs() { return (int)_cpus.size(); } json getCPU(int index); + int getMasterCPU() const { return _masterCPU; } int getNumGPUs() { return (int)_gpus.size(); } json getGPU(int index); + int getMasterGPU() const { return _masterGPU; } int getNumDisplays() { return (int)_displays.size(); } json getDisplay(int index); + int getMasterDisplay() const { return _masterDisplay; } json getMemory() { return _memory; } @@ -35,8 +40,7 @@ public: json getAll(); void virtual enumerateCpus()=0; - void virtual enumerateGpus()=0; - void virtual enumerateDisplays() {} + void virtual enumerateGpusAndDisplays()=0; void virtual enumerateNics(); void virtual enumerateMemory() = 0; void virtual enumerateComputer()=0; @@ -55,6 +59,14 @@ protected: std::vector _nics; json _memory; json _computer; + + int _masterCPU{ -1 }; + int _masterGPU{ -1 }; + int _masterDisplay{ -1 }; + + // Traverse the cpus, gpus and displays to update the "master" index in each domain + void updateMasterIndices(); + }; } // namespace platform diff --git a/libraries/platform/src/platform/backend/WINPlatform.cpp b/libraries/platform/src/platform/backend/WINPlatform.cpp index d07bb83510..e528618fe1 100644 --- a/libraries/platform/src/platform/backend/WINPlatform.cpp +++ b/libraries/platform/src/platform/backend/WINPlatform.cpp @@ -11,21 +11,31 @@ #include #include + #include -#include + +#include #ifdef Q_OS_WIN +#include +#include +#include #include #include #include #include +#include +#pragma comment(lib, "dxgi.lib") +#include +#pragma comment(lib, "Shcore.lib") + #endif using namespace platform; void WINInstance::enumerateCpus() { json cpu = {}; - + cpu[keys::cpu::vendor] = CPUIdent::Vendor(); cpu[keys::cpu::model] = CPUIdent::Brand(); cpu[keys::cpu::numCores] = std::thread::hardware_concurrency(); @@ -33,23 +43,153 @@ void WINInstance::enumerateCpus() { _cpus.push_back(cpu); } -void WINInstance::enumerateGpus() { +void WINInstance::enumerateGpusAndDisplays() { +#ifdef Q_OS_WIN + struct ConvertLargeIntegerToString { + std::string convert(const LARGE_INTEGER& version) { + std::ostringstream value; + value << uint32_t(((version.HighPart & 0xFFFF0000) >> 16) & 0x0000FFFF); + value << "."; + value << uint32_t((version.HighPart) & 0x0000FFFF); + value << "."; + value << uint32_t(((version.LowPart & 0xFFFF0000) >> 16) & 0x0000FFFF); + value << "."; + value << uint32_t((version.LowPart) & 0x0000FFFF); + + return value.str(); + } + } convertDriverVersionToString; - GPUIdent* ident = GPUIdent::getInstance(); - - json gpu = {}; - gpu[keys::gpu::model] = ident->getName().toUtf8().constData(); - gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get()); - gpu[keys::gpu::videoMemory] = ident->getMemory(); - gpu[keys::gpu::driver] = ident->getDriver().toUtf8().constData(); + // Create the DXGI factory + // Let s get into DXGI land: + HRESULT hr = S_OK; - _gpus.push_back(gpu); - _displays = ident->getOutput(); + IDXGIFactory1* pFactory = nullptr; + hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory)); + if (hr != S_OK || pFactory == nullptr) { + return; + } + + std::vector validAdapterList; + using AdapterEntry = std::pair, std::vector>; + std::vector adapterToOutputs; + // Enumerate adapters and outputs + { + UINT adapterNum = 0; + IDXGIAdapter1* pAdapter = nullptr; + while (pFactory->EnumAdapters1(adapterNum, &pAdapter) != DXGI_ERROR_NOT_FOUND) { + // Found an adapter, get descriptor + DXGI_ADAPTER_DESC1 adapterDesc; + pAdapter->GetDesc1(&adapterDesc); + + // Only describe gpu if it is a hardware adapter + if (!(adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) { + + LARGE_INTEGER version; + hr = pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version); + + std::wstring wDescription(adapterDesc.Description); + std::string description(wDescription.begin(), wDescription.end()); + + json gpu = {}; + gpu[keys::gpu::model] = description; + gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get()); + const SIZE_T BYTES_PER_MEGABYTE = 1024 * 1024; + gpu[keys::gpu::videoMemory] = (uint32_t)(adapterDesc.DedicatedVideoMemory / BYTES_PER_MEGABYTE); + gpu[keys::gpu::driver] = convertDriverVersionToString.convert(version); + + std::vector displayIndices; + + UINT outputNum = 0; + IDXGIOutput* pOutput; + bool hasOutputConnectedToDesktop = false; + while (pAdapter->EnumOutputs(outputNum, &pOutput) != DXGI_ERROR_NOT_FOUND) { + // FOund an output attached to the adapter, get descriptor + DXGI_OUTPUT_DESC outputDesc; + pOutput->GetDesc(&outputDesc); + pOutput->Release(); + outputNum++; + + // Grab the monitor info + MONITORINFO monitorInfo; + monitorInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(outputDesc.Monitor, &monitorInfo); + + // Grab the dpi info for the monitor + UINT dpiX{ 0 }; + UINT dpiY{ 0 }; + GetDpiForMonitor(outputDesc.Monitor, MDT_RAW_DPI, &dpiX, &dpiY); + UINT dpiXScaled{ 0 }; + UINT dpiYScaled{ 0 }; + GetDpiForMonitor(outputDesc.Monitor, MDT_EFFECTIVE_DPI, &dpiXScaled, &dpiYScaled); + + // Current display mode + DEVMODEW devMode; + devMode.dmSize = sizeof(DEVMODEW); + EnumDisplaySettingsW(outputDesc.DeviceName, ENUM_CURRENT_SETTINGS, &devMode); + + auto physicalWidth = devMode.dmPelsWidth / (float)dpiX; + auto physicalHeight = devMode.dmPelsHeight / (float)dpiY; + + json display = {}; + + // Display name + std::wstring wDeviceName(outputDesc.DeviceName); + std::string deviceName(wDeviceName.begin(), wDeviceName.end()); + display[keys::display::name] = deviceName; + display[keys::display::description] = ""; + + // Rect region of the desktop in desktop units + //display["desktopRect"] = (outputDesc.AttachedToDesktop ? true : false); + display[keys::display::boundsLeft] = outputDesc.DesktopCoordinates.left; + display[keys::display::boundsRight] = outputDesc.DesktopCoordinates.right; + display[keys::display::boundsBottom] = outputDesc.DesktopCoordinates.bottom; + display[keys::display::boundsTop] = outputDesc.DesktopCoordinates.top; + + // PPI & resolution + display[keys::display::physicalWidth] = physicalWidth; + display[keys::display::physicalHeight] = physicalHeight; + display[keys::display::modeWidth] = devMode.dmPelsWidth; + display[keys::display::modeHeight] = devMode.dmPelsHeight; + + //Average the ppiH and V for the simple ppi + display[keys::display::ppi] = std::round(0.5f * (dpiX + dpiY)); + display[keys::display::ppiDesktop] = std::round(0.5f * (dpiXScaled + dpiYScaled)); + + // refreshrate + display[keys::display::modeRefreshrate] = devMode.dmDisplayFrequency;; + + // Master display ? + display[keys::display::isMaster] = (bool) (monitorInfo.dwFlags & MONITORINFOF_PRIMARY); + + // Add the display index to the list of displays of the gpu + displayIndices.push_back((int) _displays.size()); + + // And set the gpu index to the display description + display[keys::display::gpu] = (int) _gpus.size(); + + // WIN specific + + + // One more display desc + _displays.push_back(display); + } + gpu[keys::gpu::displays] = displayIndices; + + _gpus.push_back(gpu); + } + + pAdapter->Release(); + adapterNum++; + } + } + pFactory->Release(); +#endif } void WINInstance::enumerateMemory() { json ram = {}; - + #ifdef Q_OS_WIN MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); @@ -60,16 +200,18 @@ void WINInstance::enumerateMemory() { _memory = ram; } -void WINInstance::enumerateComputer(){ +void WINInstance::enumerateComputer() { _computer[keys::computer::OS] = keys::computer::OS_WINDOWS; _computer[keys::computer::vendor] = ""; _computer[keys::computer::model] = ""; - - auto sysInfo = QSysInfo(); +#ifdef Q_OS_WIN + auto sysInfo = QSysInfo(); _computer[keys::computer::OSVersion] = sysInfo.kernelVersion().toStdString(); +#endif } + void WINInstance::enumerateNics() { // Start with the default from QT, getting the result into _nics: Instance::enumerateNics(); @@ -78,23 +220,23 @@ void WINInstance::enumerateNics() { // We can usually do better than the QNetworkInterface::humanReadableName() by // matching up Iphlpapi.lib IP_ADAPTER_INFO by mac id. ULONG buflen = sizeof(IP_ADAPTER_INFO); - IP_ADAPTER_INFO* pAdapterInfo = (IP_ADAPTER_INFO*) malloc(buflen); + IP_ADAPTER_INFO* pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen); // Size the buffer: if (GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) { free(pAdapterInfo); - pAdapterInfo = (IP_ADAPTER_INFO *) malloc(buflen); + pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen); } // Now get the data... if (GetAdaptersInfo(pAdapterInfo, &buflen) == NO_ERROR) { - for (json& nic : _nics) { // ... loop through the nics from above... + for (json& nic : _nics) { // ... loop through the nics from above... // ...convert the json to a string without the colons... QString qtmac = nic[keys::nic::mac].get().c_str(); QString qtraw = qtmac.remove(QChar(':'), Qt::CaseInsensitive).toLower(); // ... and find the matching one in pAdapter: for (IP_ADAPTER_INFO* pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) { - QByteArray wmac = QByteArray((const char*) (pAdapter->Address), pAdapter->AddressLength); + QByteArray wmac = QByteArray((const char*)(pAdapter->Address), pAdapter->AddressLength); QString wraw = wmac.toHex(); if (qtraw == wraw) { nic[keys::nic::name] = pAdapter->Description; @@ -108,4 +250,4 @@ void WINInstance::enumerateNics() { free(pAdapterInfo); } #endif -} \ No newline at end of file +} diff --git a/libraries/platform/src/platform/backend/WINPlatform.h b/libraries/platform/src/platform/backend/WINPlatform.h index 4926d578f7..cc56ebfbbc 100644 --- a/libraries/platform/src/platform/backend/WINPlatform.h +++ b/libraries/platform/src/platform/backend/WINPlatform.h @@ -16,7 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer () override; void enumerateNics() override; diff --git a/scripts/developer/utilities/lib/prop/PropGroup.qml b/scripts/developer/utilities/lib/prop/PropGroup.qml index 848ff8b288..c6b2c694f6 100644 --- a/scripts/developer/utilities/lib/prop/PropGroup.qml +++ b/scripts/developer/utilities/lib/prop/PropGroup.qml @@ -86,19 +86,30 @@ PropFolderPanel { var itemLabel = proItem.property; var itemDepth = root.indentDepth + 1; if (Array.isArray(itemRootObject)) { - if (objectItem.length > 1) { - itemLabel = itemLabel + " " + objectItem.length + itemLabel = proItem.property + "[] / " + itemRootObject.length + if (itemRootObject.length == 0) { + var component = Qt.createComponent("PropItem.qml"); + component.createObject(propItemsContainer, { + "label": itemLabel + }) } else { - itemLabel = itemLabel + " " + objectItem.length - itemRootObject = itemRootObject[0]; + var component = Qt.createComponent("PropGroup.qml"); + component.createObject(propItemsContainer, { + "label": itemLabel, + "rootObject":itemRootObject, + "indentDepth": itemDepth, + "isUnfold": true, + }) } + } else { + var component = Qt.createComponent("PropGroup.qml"); + component.createObject(propItemsContainer, { + "label": itemLabel, + "rootObject":itemRootObject, + "indentDepth": itemDepth, + "isUnfold": true, + }) } - var component = Qt.createComponent("PropGroup.qml"); - component.createObject(propItemsContainer, { - "label": itemLabel, - "rootObject":itemRootObject, - "indentDepth": itemDepth, - }) } break; case 'printLabel': { var component = Qt.createComponent("PropItem.qml"); @@ -125,12 +136,6 @@ PropFolderPanel { function populateFromObjectProps(object) { var propsModel = [] - if (Array.isArray(object)) { - if (object.length <= 1) { - object = object[0]; - } - } - var props = Object.keys(object); for (var p in props) { var o = {}; diff --git a/scripts/developer/utilities/render/performanceSetup.qml b/scripts/developer/utilities/render/performanceSetup.qml index 4654736f72..be9b6a3271 100644 --- a/scripts/developer/utilities/render/performanceSetup.qml +++ b/scripts/developer/utilities/render/performanceSetup.qml @@ -51,6 +51,7 @@ Rectangle { } Prop.PropFolderPanel { label: "Platform" + isUnfold: true panelFrameData: Component { Platform { }