Gerenciamento de energia e térmicas

Quando o HoloLens 2 está em execução em ambientes quentes ou com requisitos de desempenho intenso (uso de CPU/GPU, uso de periféricos etc.), pode ficar quente o suficiente para que ele execute ações automaticamente para evitar superaquecimento. Essas ações incluem itens como:

  • Ajustando o desempenho de carregamento
  • Fornecer comentários do usuário
  • Fechando aplicativos

... e, na pior das hipóteses, cenários:

  • Desligando o HoloLens 2

Se o aplicativo exigir alto desempenho periférico, considere usar o SDK (Software Development Kit) PowerThermalNotification para assinar eventos de notificação e implementar suas próprias ações personalizadas. Isso pode permitir que o dispositivo opere mais em situações em que, caso contrário, um aplicativo poderá ser encerrado pelo sistema.

Observação

O suporte para o SDK Microsoft.MixedReality.PowerThermalNotification está incluído na versão 22H1.

Este artigo descreve o SDK do PowerThermalNotification e seu uso básico para começar.

Onde posso obter o SDK?

O SDK do PowerThermalNotification pode ser baixado por meio da Ferramenta de Recursos do Realidade Misturada.

O SDK do PowerThermalNotification dá suporte a projeções de linguagem para C# e C++, permitindo que os desenvolvedores desenvolvam aplicativos para plataformas Win32 ou UWP.

Visão geral conceitual

A energia consumida pela HoloLens 2 é dissipada no calor. Um dispositivo de computador tradicional teria um ventilador para resolver isso, mas um dispositivo vestível deve ser leve. Por isso, a solução de resfriamento é mais complexa. HoloLens 2 tem recursos internos de segurança de hardware e software para garantir que o headset não fique muito quente para o usuário, mas esses recursos também devem ser equilibrados com a experiência do usuário. Por exemplo, se soubermos qual parte do HoloLens 2 está aquecendo, podemos optar por limitar os periféricos responsáveis por esse calor. Como último recurso, podemos fechar um aplicativo que se acredita ser responsável pelo poder que levou a esse calor.

HoloLens 2 lida com problemas de calor usando sensores de temperatura. Uma estrutura térmica vincula grupos de sensores a diferentes periféricos no dispositivo. Os sensores são agrupados porque pode ser impossível determinar qual periférico em uma área física é responsável pelo desenho de energia que aquece o HoloLens 2.

O SDK do PowerThermalNotification expõe as APIs necessárias para monitorar esses grupos de sensores. Os eventos do SDK são acionados quando um periférico que está sendo usado pelo aplicativo mostra sinais de que uma mitigação pode ser necessária. Em seguida, o aplicativo pode adaptar sua experiência com o cliente para reduzir o impacto térmico. Reduzir o impacto significa menos risco de ação do sistema, como desligamento do aplicativo ou do dispositivo.

Um exemplo simples seria um aplicativo que está usando a CPU para processar uma grande quantidade de dados de vídeo. O aplicativo pode assinar uma notificação de desempenho para o componente de CPU. Quando o aplicativo recebe uma notificação, ele pode reduzir a carga de trabalho da CPU. Se outro evento for recebido que indica que nenhuma mitigação adicional é necessária, a carga de trabalho da CPU poderá ser restaurada.

Resposta da plataforma

A tabela a seguir é um detalhamento das ações do sistema por periférico. As ações descritas abaixo podem ser suprimidas usando o SDK. Consulte Suprimindo mitigações padrão do sistema

Periférico MinimumUserImpact MediumUserImpact MaximumUserImpact Último Recurso Desligamento de software Failsafe
GPU Limitar o intervalo vsync de ajuste de qualidade
do MRC
Exibir Redução de FPS de profundidade
Qualquer periférico Exibir Aviso
Fechar Captura mrc de parada de aplicativo
Desligamento do sistema operacional Desligamento de hardware

Observação

Ações nas colunas "Último Recurso", "Desligamento de Software" e "Failsafe" não podem ser suprimidas.

Sugestões para resposta do aplicativo

Veja a seguir um detalhamento das mitigações sugeridas que um aplicativo pode adotar com base em quais periféricos precisam de mitigação. Cabe ao desenvolvedor de aplicativos determinar quais dessas ações podem ter um efeito mais significativo em cada periférico, já que cada aplicativo é diferente. Os desenvolvedores devem priorizar as ações que tomam com base no impacto para o usuário final.

Mitigações sugeridas por periférico

CPU

GPU

DRAM

Rede

Bateria

Exibir

  • Aumentar o número de pixels pretos na cena
  • Usar cores de baixa potência (por exemplo, verde)
  • Esmaecer a tela

Câmera de foto/vídeo

  • Visão geral
  • Reduzir a resolução da câmera
  • Reduzir a taxa de quadros da câmera
  • Reduzir o pós-processamento de imagens da câmera do aplicativo
  • Parar de usar a câmera de foto/vídeo

Casos de uso de implementação

O SDK foi projetado para dar suporte a dois casos de uso padrão para obter informações:

  • Baseada em evento
  • Baseado em sondagem

A notificação baseada em evento fornecerá o caminho de comentários mais rápido para o aplicativo, caso ele precise executar uma ação. No entanto, em alguns casos, pode ser mais conveniente para o desenvolvedor usar a sondagem.

Observação

As informações de estado são atualizadas, no máximo, a cada poucos segundos para cada periférico, portanto, sondar mais rápido do que isso pode desperdiçar ciclos de CPU.

Uso de API baseada em evento

Registrar-se em eventos

Para obter notificações, há três requisitos:

Você não receberá eventos se seu aplicativo não atender a esses requisitos.

O primeiro item pode ser verificado usando a função IsSupported . Se o sistema der suporte a notificações para pelo menos um dos periféricos na máscara, a função retornará true. Você pode optar por não marcar suporte ao uso dessa função, desde que seu aplicativo não dependa explicitamente dos eventos do SDK do PowerThermalNotification.

Depois de atender aos três requisitos acima, você receberá notificações iniciais para todos os PeriféricosOfInterest com suporte. Se você alterar PeriféricosOfInterest ou qualquer um dos manipuladores de eventos, receberá outro conjunto de notificações com base no status atual.

Aqui está um snippet de código para capturar a instância da classe PowerThermalNotification e configurá-la para notificações para PowerThermalPeripheralFlags.Cpu e PowerThermalPeripheralFlags.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;
    }  
}

Manipulação de eventos

Quando o evento PowerThermalMitigationLevelChanged é acionado , ele vem com PowerThermalEventArgs. Eles devem ser usados para entender o evento.

Da mesma forma, quando o evento PowerThermalThermalScoreChanged é acionado , ele vem com PowerThermalScoreArgs.

Quando um evento é recebido, o manipulador de eventos deve inspecionar args. ImpactedPeripherals, que identifica quais periféricos são afetados (pode haver mais de um).

Para eventos PowerThermalMitigationLevelChanged , os args. MitigationLevel indica o quão grave de uma mitigação é recomendada para os periféricos especificados. Se o args. MitigationLevel é PowerThermalMitigationLevel.NoUserImpact e todas as mitigações associadas aos periféricos especificados devem ser removidas.

Para eventos PowerThermalThermalScoreChanged , os args. ThermalScore indica uma pontuação de 100 a 0 refletindo uma escala linear se aproximando de um evento de desligamento do aplicativo (zero). O intervalo de Pontuação Térmica começa fora do intervalo de relatórios de mitigação para permitir notificação anterior ao aplicativo ao abordar a necessidade de mitigações.

Aqui está um manipulador de exemplo:

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);
    }
}

Observação

O parâmetro ImpactedPeripherals de args identifica apenas os periféricos que foram afetados E parte de PeripheralsOfInterest. Outros periféricos afetados que não foram incluídos em PeripheralsOfInterest não serão identificados.

Observação

Os níveis de mitigação para periféricos têm histerese. Depois que o nível aumenta, ele não diminui até que seja liberado. A versão é um evento com args. MitigationLevel definido como PowerThermalMitigationLevel.NoUserImpact.

Reunindo-o (modelo baseado em evento)

Aqui está um exemplo simples de um conjunto de scripts que podem ser usados no Unity para habilitar essa funcionalidade. A classe NotificationComponent pode ser adicionada a qualquer objeto de jogo e esse objeto de jogo pode acompanhar o nível de mitigação do periférico atribuído. A classe NotificationManager lida com o SDK que gerencia assinaturas por meio da instância única da classe PowerThermalNotification .

Aqui está a classe 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;
        }
    }
}

Aqui está a classe 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);
    }

}

Uso da API baseada em sondagem

Atualizando periféricos de interesse

Semelhante ao uso baseado em evento, a definição da propriedade PeripheralsOfInterest é necessária para sondar um determinado periférico.

Aviso

Se você tentar chamar GetLastPeripheralState para um determinado periférico sem primeiro definir esse sinalizador em PeripheralsOfInterest, uma exceção será gerada. Da mesma forma, se você tentar usar GetLastPeripheralState com um valor inválido (vários bits de sinalizador definidos ou um bit sem suporte), uma exceção será gerada.

Chamando as APIs de sondagem

Depois que PeripheralsOfInterest tiver os bits periféricos definidos que você deseja sondar, você poderá chamar GetLastPeripheralState.

O PowerThermalPeripheralState retornado contém os valores mais recentes para Pontuação Térmica e Nível de Mitigação para o periférico fornecido.

Observação

É possível que, em plataformas futuras, determinados periféricos não sejam suportados. Nesses casos, a API retornará uma Pontuação Térmica de 100 e um Nível de Mitigação de NoUserImpact. O aplicativo pode marcar o campo IsSupportedPeripheral da estrutura para marcar se esse é ou não o caso de um determinado periférico.

Consulte Manipulando eventos para obter detalhes sobre como lidar com a Pontuação Térmica e MitigaçãoLevel retornada por PowerThermalPeripheralState.

Aqui está um pequeno snippet mostrando a sondagem:

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";
    }
}

Suprimir mitigações padrão do sistema

Se você não quiser que o sistema tente atenuar determinados periféricos, poderá suprimi-los. Para fazer isso, basta atualizar a propriedade SuppressedPlatformMitigationForPeripherals ou chamar a função SuppressPlatformMitigation .

Aqui está um pequeno snippet:

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);

Observação

As APIs de supressão só funcionarão se o processo que usa a classe PowerThermalNotification estiver em primeiro plano. Os processos em segundo plano ainda podem assinar eventos, mas podem não desabilitar HoloLens 2 ações.

Teste

Depois de integrar o SDK ao aplicativo, você desejará testá-lo. Para sistemas operacionais HoloLens 2 que dão suporte ao SDK, uma página de desenvolvedor estará disponível no Portal do Dispositivo. Nesta página, você pode controlar os níveis de mitigação e as pontuações térmicas para cada periférico. Você também pode monitorar quais periféricos têm mitigações sendo suprimidas ativamente.

Você também pode aproveitar as APIs REST para monitorar/testar níveis de mitigação e pontuações térmicas de outro dispositivo. Mais informações podem ser encontradas na Referência de API do Portal de Dispositivos