管理電源和熱力

當HoloLens 2在暖環境中執行,或具有大量效能需求時, (CPU/GPU 使用量、周邊使用量等) ,它可能會變得很忙碌,讓它自動採取動作,使其無法保持忙碌狀態。 這些動作包括下列專案:

  • 調整充電效能
  • 提供使用者意見反應
  • 關閉應用程式

...在最差案例中:

  • 關閉HoloLens 2

如果您的應用程式需要高周邊效能,請考慮使用 PowerThermalNotification 軟體發展工具組 (SDK) 訂閱通知事件,並實作您自己的自訂動作。 這樣做可讓裝置在系統可能終止的情況下運作較長的時間。

注意

22H1 版本中包含 Microsoft.MixedReality.PowerThermalNotification SDK 的支援。

本文說明 PowerThermalNotification SDK 及其基本用法,讓您開始使用。

哪裡可以取得 SDK?

PowerThermalNotification SDK 可透過Mixed Reality功能工具下載。

PowerThermalNotification SDK 支援 C# 和 C++ 的語言投影,可讓開發人員開發 Win32 或 UWP 平臺的應用程式。

概念概觀

HoloLens 2耗用的電源會在熱度中消失。 傳統電腦裝置會有風扇來解決此問題,但穿戴式裝置必須是輕量型裝置。 因此,冷卻解決方案更為複雜。 HoloLens 2具有內建的硬體和軟體安全性功能,以確保頭戴式裝置不會對使用者太忙碌,但這些功能也必須與使用者體驗進行平衡。 例如,如果我們知道哪一部分的HoloLens 2正在加速,我們可以選擇節流負責此熱度的周邊。 最後,我們可能會關閉一個認為負責導致此熱度之電源的應用程式。

HoloLens 2使用溫度感應器來處理熱度問題。 熱架構會將感應器群組系結至裝置上的不同周邊。 感應器會分組,因為可能無法判斷實體區域中的哪些周邊負責產生HoloLens 2的電源繪製。

PowerThermalNotification SDK 會公開監視這些感應器群組所需的 API。 當應用程式所使用的周邊顯示可能需要風險降低的徵兆時,就會引發 SDK 事件。 應用程式接著可以調整其客戶體驗,以減少熱影響。 降低影響表示系統動作的風險較低,例如應用程式或裝置關機。

簡單的範例是使用 CPU 來處理大量視訊資料的應用程式。 應用程式可以訂閱 CPU 元件的效能通知。 當應用程式收到通知時,它可以減少 CPU 工作負載。 如果收到另一個事件,表示不需要進一步的風險降低,則可以還原 CPU 工作負載。

平臺回應

下表是周邊系統動作的明細。 以下所述的動作可以使用 SDK 來隱藏。 請參閱 隱藏預設系統防護功能

周邊設備 MinimumUserImpact MediumUserImpact MaximumUserImpact Last Resort 軟體關機 故障
GPU 節流 MRC 品質
調整 VSYNC 間隔
顯示 深度 FPS 縮小
任何周邊 顯示警告
關閉應用程式
停止 MRC 擷取
OS 關機 硬體關機

注意

無法隱藏 「Last Resort」、「Software Shutdown」 和 「Failsafe」 資料行中的動作。

應用程式回應的建議

以下是應用程式可以根據需要風險降低的周邊 () 採取的建議風險降低措施明細。 應用程式開發人員必須判斷這些動作對每個周邊的哪些動作可能會有更大的影響,因為每個應用程式都不同。 開發人員應該根據對使用者的影響來排定其採取動作的優先順序。

周邊建議的防護功能

CPU

GPU

DRAM

網路

電池

顯示

  • 增加場景中黑色圖元的數目
  • 例如,使用低電源色彩 (綠色)
  • 將顯示器變暗

相片/視訊相機

  • 概觀
  • 減少相機解析度
  • 減少相機畫面播放速率
  • 減少相機影像的後續處理應用程式
  • 停止使用相片/視訊相機

實作使用案例

SDK 的設計目的是要支援兩個標準使用案例來取得資訊:

  • 事件型
  • 輪詢型

事件型通知會提供應用程式最快速的意見反應路徑,以防應用程式需要採取動作。 不過,在某些情況下,開發人員可能更方便使用輪詢。

注意

狀態資訊最多會針對每個周邊每隔幾秒更新一次,因此輪詢速度會比浪費 CPU 週期還要快。

事件型 API 使用方式

註冊事件

若要取得通知,有三個需求:

如果您的應用程式不符合這些需求,您將不會收到事件。

您可以使用 IsSupported 函式來檢查第一個專案。 如果系統支援遮罩中至少一個周邊的通知,則函式會傳回 true。 只要您的應用程式未明確相依于 PowerThermalNotification SDK 事件,您就可以選擇不要使用此函式來檢查支援。

符合上述三個需求之後,您會收到所有支援的 PeripheralsOfInterest的初始通知。 如果您稍後變更 PeripheralsOfInterest 或任一事件處理常式,您將會根據目前狀態收到另一組通知。

以下是擷取 PowerThermalNotification 類別實例的程式碼片段,並將其設定為 PowerThermalPeripheralFlags.CpuPowerThermalPeripheralFlags.PhotoVideoCamera的通知:

using Microsoft.MixedReality.PowerThermalNotification;

private void NotificationHandler(object sender, PowerThermalEventArgs args)
{
    //  Notification handling can be done here using information contained in args
}

private void InitializeThermalNotifications()
{
    PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
    
    PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;
     if (PowerThermalNotification.IsSupported(requestedFlags))
    {
        //At least one of these peripherals is supported by the system
        p.PeripheralsOfInterest = requestedFlags;
        p.PowerThermalMitigationLevelChanged += NotificationHandler;
    }  
}

錯誤事件

PowerThermalMitigationLevelChanged 事件引發時,隨附 PowerThermalEventArgs。 這些應該用來瞭解事件。

同樣地,當 PowerThermalThermalScoreChanged 事件引發時,它隨附 PowerThermalScoreArgs

收到事件時,事件處理常式應該檢查 引數。ImpactedPeripherals,可識別哪些周邊 () 受到影響, (可能有一個以上的) 。

若為 PowerThermalMitigationLevelChanged 事件, 則為引數。MitigationLevel 指出針對指定的周邊建議風險降低程度。 如果 引數。MitigationLevelPowerThermalMitigationLevel.NoUserImpact ,然後應該移除與指定周邊相關聯的任何風險降低。

若為 PowerThermalThermalScoreChanged 事件, 則為 args。熱核心 表示從 100 到 0 的分數,反映接近應用程式關機事件的線性刻度, (零) 。 熱分數範圍會從風險降低報告範圍之外開始,以便在接近風險降低需求時,允許對應用程式的先前通知。

以下是範例處理常式:

bool doCpuThrottle = false;

private void NotificationHandler(object sender, PowerThermalEventArgs args)
{
    if (args.ImpactedPeripherals.HasFlag(PowerThermalPeripheralFlags.Cpu))
    {
        if(args.MitigationLevel = PowerThermalMitigationLevel.NoUserImpact)
        {
            doCpuThrottle = false;
        }
        else if(args.MitigationLevel >= PowerThermalMitigationLevel.MinimumUserImpact)
        {
            // Note that this only kicks in at MinimumUserImpact and does not get released until NoUserImpact
            doCpuThrottle = true;
        }
    }

    if (args.ImpactedPeripherals.HasFlag(PowerThermalPeripheralFlags.PhotoVideoCamera))
    {
        SetMitigationStatus(PhotoVideoCameraStatusText, PhotoVideoRectangle, args.MitigationLevel);
    }
}

注意

args 的 ImpactedPeripherals 參數只會識別兩者都受影響的周邊,以及 PeripheralsOfInterest 的一部分。 不會識別未包含在 PeripheralsOfInterest 中的其他受影響周邊。

注意

周邊的緩和等級具有連字號。 一旦層級增加,它才會在發行之前減少。 發行是具有 args 的事件。MitigationLevel 設定為 PowerThermalMitigationLevel.NoUserImpact。

將它結合在一起 (事件型模型)

以下是一組可在 Unity 中用來啟用這項功能的簡單腳本範例。 NotificationComponent 類別可以新增至任何遊戲物件,而該遊戲物件可以追蹤指派周邊的風險降低等級。 NotificationManager 類別會透過PowerThermalNotification類別的單一實例來處理 SDK 管理訂用帳戶。

以下是 NotificationManager 類別:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using Microsoft.MixedReality.PowerThermalNotification;

public class NotificationManager
{
    private static readonly object listLock = new object();
    private static List<NotificationComponent> components = new List<NotificationComponent>();
    private static PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
    private static bool FirstTime = true;

    private static void NotificationHandler(object sender, PowerThermalEventArgs args)
    {
        lock (listLock)
        {
            foreach (NotificationComponent c in components)
            {
                UnityEngine.WSA.Application.InvokeOnAppThread(() =>
                {
                    c.SetMitigationLevel(args.ImpactedPeripherals, args.MitigationLevel);
                }, false);
            }
        } 
    }

    public static void ChangeSuppression(PowerThermalPeripheralFlags peripherals, bool suppress)
    {
        p.SuppressPlatformMitigation(peripherals, suppress);
    }

    public static void AddNotification(NotificationComponent component, PowerThermalPeripheralFlags peripheralsOfInterest)
    {
        if (FirstTime)
        {
            p.PowerThermalMitigationLevelChanged += NotificationHandler;
            FirstTime = false;
        }
        
        if (PowerThermalNotification.IsSupported(peripheralsOfInterest))
        {
            lock (listLock)
            {
                component.SetMitigationLevel(peripheralsOfInterest, (PowerThermalMitigationLevel)0);
                components.Add(component);
            }
            p.PeripheralsOfInterest |= peripheralsOfInterest;
        }
    }
}

以下是 NotificationComponent 類別:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Microsoft.MixedReality.PowerThermalNotification;

public class NotificationComponent : MonoBehaviour
{
    //Note that this could be multiple peripherals, just need to make sure to look at impactedPeripherals in the handler
    public PowerThermalPeripheralFlags monitoredPeripheral = (PowerThermalPeripheralFlags) 0;
    public bool isSuppressed = false;

    public void SetMitigationLevel(PowerThermalMitigationLevel level)
    {
        Color newColor = Color.white;

        if (level == PowerThermalMitigationLevel.NoUserImpact)
        {
            newColor = Color.green;
        }
        else if (level == PowerThermalMitigationLevel.MinimumUserImpact)
        {
            newColor = Color.yellow;
        }
        else if (level == PowerThermalMitigationLevel.MediumUserImpact)
        {
            newColor = new Color32(255, 127, 37, 255);//Orange
        }
        else
        {
            newColor = Color.red;
        }

        MaterialPropertyBlock props = new MaterialPropertyBlock();
        props.SetColor("_Color", newColor);
        GetComponent<Renderer>().SetPropertyBlock(props);
    }

    public void SetMitigationLevel(PowerThermalPeripheralFlags impactedPeripherals, PowerThermalMitigationLevel level)
    {
        if (impactedPeripherals.HasFlag(monitoredPeripheral))
        {
            SetMitigationLevel(level);
        }
    }

    void Start()
    {
        NotificationManager.AddNotification(this, monitoredPeripheral);
        NotificationManager.ChangeSuppression(monitoredPeripheral, isSuppressed);
    }

}

輪詢型 API 使用量

更新感興趣的周邊

類似于事件型使用方式,需要設定 PeripheralsOfInterest 屬性才能輪詢指定的周邊。

警告

如果您嘗試針對指定的周邊呼叫 GetLastPeripheralState ,而不需先在 PeripheralsOfInterest中設定該旗標,則會擲回例外狀況。 同樣地,如果您嘗試使用 GetLastPeripheralState 與設定多個旗標位 (不正確值,或) 不支援的位,則會擲回例外狀況。

呼叫輪詢 API

一旦 PeripheralsOfInterest具有您想要輪詢的周邊位 () 集,您就可以呼叫GetLastPeripheralState

傳回的 PowerThermalPeripheralState 包含指定周邊熱分數和風險降低等級的最新值。

注意

未來平臺可能不支援某些周邊。 在這些情況下,API 會傳回熱分數 100 和 NoUserImpact 的風險降低等級。 應用程式可以檢查結構的 IsSupportedPeripheral 欄位,以檢查指定的周邊是否為這種情況。

如需處理PowerThermalPeripheralState所傳回之熱分數MitigationLevel的詳細資訊,請參閱處理事件

以下是顯示輪詢的小型程式碼片段:

private async void timerCallback(object state)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();

        PowerThermalPeripheralState CpuState = p.GetLatestPeripheralState(PowerThermalPeripheralFlags.Cpu);
        PowerThermalPeripheralState PhotoVideoCameraState = p.GetLatestPeripheralState(PowerThermalPeripheralFlags.PhotoVideoCamera);
        
        CpuScoreText.Text = CpuState.ThermalScore.ToString();
        PhotoVideoScoreText.Text = PhotoVideoCameraState.ThermalScore.ToString();
    });
}

private void InitializeThermalNotifications()
{
    PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();

    PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;
    p.SuppressedPlatformMitigationForPeripherals = requestedFlags;//Suppress any platform mitigation on CPU or PhotoVideoCamera

    if (PowerThermalNotification.IsSupported(requestedFlags))
    {
        p.PeripheralsOfInterest = requestedFlags;

        Timer timer = new Timer(timerCallback, null, 0, 3000);
    }
    else
    {
        TitleLabel.Text = "Not Supported";
    }
}

隱藏預設系統風險降低

如果您不想讓系統嘗試減輕某些周邊,您可以隱藏它們。 若要這樣做,只要更新 SuppressedPlatformMitigationForPeripherals 屬性,或呼叫 SuppressPlatformMitigation 函式 即可。

以下是一個小程式碼片段:

PowerThermalNotification p = PowerThermalNotification.GetForCurrentProcess();
PowerThermalPeripheralFlags requestedFlags = PowerThermalPeripheralFlags.Cpu | PowerThermalPeripheralFlags.PhotoVideoCamera;

//You can do this to set the property explicitly
p.SuppressedPlatformMitigationForPeripherals = requestedFlags;

//Or you can do this to manipulate the property mask. 
//This specific example clears the CPU, leaving the PhotoVideoCamera suppressed
p.SuppressPlatformMitigation(PowerThermalPeripheralFlags.Cpu, false);

注意

只有在使用 PowerThermalNotification 類別的進程位於前景時,隱藏 API 才能運作。 背景進程仍然可以訂閱事件,但可能不會停用HoloLens 2動作。

測試

將 SDK 整合到您的應用程式之後,您會想要測試它。 針對支援 SDK 的HoloLens 2作業系統,裝置入口網站中將會提供開發人員頁面。 您可以從此頁面控制每個周邊的風險降低等級和熱分數。 您也可以監視哪些周邊有主動隱藏的風險降低。

您也可以利用 REST API 來監視/測試來自另一部裝置的風險降低等級和熱分數。 如需詳細資訊,請參閱 裝置入口網站 API 參考