Partilhar via


Melhorias no Direct3D 9Ex

Este tópico descreve o suporte adicionado do Windows 7 para o Modo Flip Present e suas estatísticas atuais associadas no Direct3D 9Ex e no Desktop Window Manager. Os aplicativos de destino incluem aplicativos de apresentação baseados em vídeo ou taxa de quadros. Os aplicativos que usam o Direct3D 9Ex Flip Mode Present reduzem a carga de recursos do sistema quando o DWM está habilitado. Os aprimoramentos de estatísticas atuais associados ao Modo Flip Present permitem que os aplicativos Direct3D 9Ex controlem melhor a taxa de apresentação, fornecendo feedback em tempo real e mecanismos de correção. Explicações detalhadas e indicações para recursos de amostra estão incluídas.

Este tópico contém as seguintes seções.

O que melhorou no Direct3D 9Ex para Windows 7

O Modo Flip Presentation do Direct3D 9Ex é um modo melhorado de apresentação de imagens no Direct3D 9Ex que transfere eficientemente imagens renderizadas para o Windows 7 Desktop Window Manager (DWM) para composição. A partir do Windows Vista, o DWM compõe toda a área de trabalho. Quando o DWM está ativado, os aplicativos de modo de janela apresentam seu conteúdo na área de trabalho usando um método chamado Blt Mode Present to DWM (ou Blt Model). Com o Modelo Blt, o DWM mantém uma cópia da superfície renderizada Direct3D 9Ex para composição da área de trabalho. Quando o aplicativo é atualizado, o novo conteúdo é copiado para a superfície DWM através de um blt. Para aplicativos que contêm conteúdo Direct3D e GDI, os dados GDI também são copiados para a superfície DWM.

Disponível no Windows 7, o Flip Mode Present to DWM (ou Flip Model) é um novo método de apresentação que essencialmente permite a passagem de identificadores de superfícies de aplicativos entre aplicativos de modo de janela e DWM. Além de economizar recursos, o Flip Model suporta estatísticas atuais aprimoradas.

As estatísticas atuais são informações de temporização de quadros que os aplicativos podem usar para sincronizar fluxos de vídeo e áudio e recuperar de falhas de reprodução de vídeo. As informações de tempo de quadros nas estatísticas atuais permitem que os aplicativos ajustem a taxa de apresentação de seus quadros de vídeo para uma apresentação mais suave. No Windows Vista, onde o DWM mantém uma cópia correspondente da superfície do quadro para composição da área de trabalho, os aplicativos podem usar estatísticas atuais fornecidas pelo DWM. Este método de obtenção de estatísticas atuais ainda estará disponível no Windows 7 para aplicativos existentes.

No Windows 7, os aplicativos baseados no Direct3D 9Ex que adotam o Flip Model devem usar APIs D3D9Ex para obter estatísticas atuais. Quando o DWM está ativado, os aplicativos Direct3D 9Ex do modo de janela e exclusivo de tela cheia podem esperar as mesmas informações estatísticas presentes ao usar o Flip Model. As estatísticas presentes do Direct3D 9Ex Flip Model permitem que os aplicativos consultem estatísticas atuais em tempo real, em vez de depois que o quadro for mostrado na tela; As mesmas informações estatísticas atuais estão disponíveis para aplicativos habilitados para Flip-Model em modo de janela como aplicativos em tela cheia; um sinalizador adicionado nas APIs D3D9Ex permite que os aplicativos Flip Model eliminem efetivamente quadros atrasados no momento da apresentação.

O Direct3D 9Ex Flip Model deve ser usado por novos aplicativos de apresentação baseados em vídeo ou taxa de quadros destinados ao Windows 7. Devido à sincronização entre o DWM e o tempo de execução do Direct3D 9Ex, os aplicativos que usam o Flip Model devem especificar entre 2 a 4 backbuffers para garantir uma apresentação suave. Os aplicativos que usam as informações de estatísticas presentes se beneficiarão do uso de aprimoramentos de estatísticas presentes habilitados para Flip Model.

Apresentação do Modo Flip Direct3D 9EX

As melhorias de desempenho do Direct3D 9Ex Flip Mode Present são significativas no sistema quando o DWM está ligado e quando o aplicativo está no modo de janela, em vez de no modo exclusivo de tela cheia. A tabela e a ilustração a seguir mostram uma comparação simplificada dos usos de largura de banda de memória e leituras e gravações do sistema de aplicativos em janela que escolhem Flip Model versus o Blt Model de uso padrão.

Modo Blt presente ao DWM Modo Flip D3D9Ex Presente ao DWM
1. O aplicativo atualiza seu quadro (Gravação)
1. O aplicativo atualiza seu quadro (Gravação)
2. O tempo de execução do Direct3D copia o conteúdo da superfície para uma superfície de redirecionamento DWM (leitura, gravação)
2. O tempo de execução do Direct3D passa a superfície do aplicativo para o DWM
3. Após a conclusão da cópia da superfície compartilhada, o DWM renderiza a superfície do aplicativo na tela (Leitura, Gravação)
3. DWM renderiza a superfície do aplicativo na tela (leitura, gravação)

ilustração de uma comparação entre o modelo BLT e o modelo flip

O Modo Flip Present reduz o uso da memória do sistema, reduzindo o número de leituras e gravações pelo tempo de execução do Direct3D para a composição de quadros em janela pelo DWM. Isso reduz o consumo de energia do sistema e o uso geral de memória.

Os aplicativos podem aproveitar o Direct3D 9Ex Flip Mode apresentar aprimoramentos de estatísticas quando o DWM está ativado, independentemente de o aplicativo estar no modo de janela ou no modo exclusivo de tela cheia.

Modelo de programação e APIs

Novos aplicativos de vídeo ou medição de taxa de quadros que usam APIs do Direct3D 9Ex no Windows 7 podem aproveitar a economia de memória e energia e a apresentação aprimorada oferecida pelo Modo Flip Present quando executado no Windows 7. (Quando executado em versões anteriores do Windows, o tempo de execução do Direct3D padroniza o aplicativo para o Modo Blt Presente.)

O Flip Mode Present implica que o aplicativo pode aproveitar os mecanismos de feedback e correção de estatísticas presentes em tempo real quando o DWM está ativado. No entanto, os aplicativos que usam o Flip Mode Present devem estar cientes das limitações quando usam renderização simultânea da API GDI.

Você pode modificar os aplicativos existentes para aproveitar o Modo Flip Present, com os mesmos benefícios e ressalvas dos aplicativos recém-desenvolvidos.

Como optar pelo modelo Direct3D 9Ex Flip

Os aplicativos Direct3D 9Ex destinados ao Windows 7 podem optar pelo modelo Flip criando a cadeia de permuta com o valor de enumeração D3DSWAPEFFECT_FLIPEX. Para optar pelo Flip Model, os aplicativos especificam a estrutura D3DPRESENT_PARAMETERS e, em seguida, passam um ponteiro para essa estrutura quando chamam a IDirect3D9Ex::CreateDeviceEx API. Esta seção descreve como os aplicativos destinados ao Windows 7 usam IDirect3D9Ex::CreateDeviceEx optar pelo Modelo Flip. Para obter mais informações sobre o IDirect3D9Ex::CreateDeviceEx API, consulte IDirect3D9Ex::CreateDeviceEx no MSDN.

Por conveniência, a sintaxe de D3DPRESENT_PARAMETERS e IDirect3D9Ex::CreateDeviceEx é repetida aqui.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);
typedef struct D3DPRESENT_PARAMETERS {
    UINT BackBufferWidth, BackBufferHeight;
    D3DFORMAT BackBufferFormat;
    UINT BackBufferCount;
    D3DMULTISAMPLE_TYPE MultiSampleType;
    DWORD MultiSampleQuality;
    D3DSWAPEFFECT SwapEffect;
    HWND hDeviceWindow;
    BOOL Windowed;
    BOOL EnableAutoDepthStencil;
    D3DFORMAT AutoDepthStencilFormat;
    DWORD Flags;
    UINT FullScreen_RefreshRateInHz;
    UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;

Quando você modifica aplicativos Direct3D 9Ex para Windows 7 para optar pelo modelo Flip, você deve considerar os seguintes itens sobre os membros especificados do D3DPRESENT_PARAMETERS:

BackBufferCount

(Apenas Windows 7)

Quando SwapEffect é definido como o novo tipo de efeito de cadeia de permuta de D3DSWAPEFFECT_FLIPEX, a contagem de buffer traseiro deve ser igual ou maior que 2, para evitar uma penalidade de desempenho do aplicativo como resultado da espera no buffer Presente anterior a ser liberado pelo DWM.

Quando o aplicativo também usa estatísticas atuais associadas a D3DSWAPEFFECT_FLIPEX, recomendamos que você defina a contagem de buffer de volta para de 2 a 4.

O uso do D3DSWAPEFFECT_FLIPEX no Windows Vista ou em versões anteriores do sistema operacional retornará falha do CreateDeviceEx.

SwapEffect

(Apenas Windows 7)

O novo tipo de efeito de cadeia de permuta D3DSWAPEFFECT_FLIPEX designa quando um aplicativo está adotando o Modo Flip Present para DWM. Ele permite que o aplicativo use mais eficientemente a memória e energia, e também permite que o aplicativo aproveite as estatísticas presentes em tela cheia no modo de janela. O comportamento do aplicativo em tela cheia não é afetado. Se Windowed estiver definido como TRUE e SwapEffect estiver definido como D3DSWAPEFFECT_FLIPEX, o tempo de execução criará um buffer traseiro extra e girará o identificador que pertencer ao buffer que se torna o buffer frontal no momento da apresentação.

Bandeiras

(Apenas Windows 7)

O sinalizador D3DPRESENTFLAG_LOCKABLE_BACKBUFFER não pode ser definido se SwapEffect estiver definido para o novo tipo de efeito de cadeia de permuta D3DSWAPEFFECT_FLIPEX.

Diretrizes de design para aplicativos Direct3D 9Ex Flip Model

Use as diretrizes nas seções a seguir para projetar seus aplicativos Direct3D 9Ex Flip Model.

Use o Modo Flip Presente em um HWND separado do Modo Blt Presente

Os aplicativos devem usar o Direct3D 9Ex Flip Mode Present em um HWND que não seja também direcionado por outras APIs, incluindo o Blt Mode Present Direct3D 9Ex, outras versões do Direct3D ou GDI. Flip Mode Present pode ser usado para apresentar a janelas de crianças; ou seja, os aplicativos podem usar o Flip Model quando ele não está misturado com o Blt Model no mesmo HWND, como mostrado nas ilustrações a seguir.

ilustração da janela pai Direct3D e uma janela filho GDI, cada uma com seu próprio HWND

ilustração da janela pai GDI e uma janela filho Direct3D, cada uma com seu próprio HWND

Como o Modelo Blt mantém uma cópia adicional da superfície, o GDI e outros conteúdos Direct3D podem ser adicionados ao mesmo HWND por meio de atualizações fragmentadas do Direct3D e GDI. Usando o modelo Flip, apenas o conteúdo Direct3D 9Ex em D3DSWAPEFFECT_FLIPEX cadeias de permuta que são passadas para DWM será visível. Todas as outras atualizações de conteúdo do Modelo Blt Direct3D ou GDI serão ignoradas, conforme mostrado nas ilustrações a seguir.

ilustração do texto GDI que pode não ser exibido se o modelo FLIP for usado e o conteúdo Direct3D e GDI estiver no mesmo HWND

ilustração do conteúdo Direct3D e GDI no qual o DWM está habilitado e o aplicativo está no modo de janela

Portanto, o Flip Model deve ser habilitado para superfícies de buffers de cadeia de permuta onde o Direct3D 9Ex Flip Model sozinho renderiza para todo o HWND.

Não use Flip Model com ScrollWindow ou ScrollWindowEx da GDI

Alguns aplicativos Direct3D 9Ex usam as funções ScrollWindow ou ScrollWindowEx do GDI para atualizar o conteúdo da janela quando um evento de rolagem do usuário é acionado. ScrollWindow e ScrollWindowEx executam blts do conteúdo da janela na tela enquanto uma janela é rolada. Essas funções também exigem atualizações do modelo Blt para conteúdo GDI e Direct3D 9Ex. Os aplicativos que usam qualquer uma das funções não necessariamente exibirão o conteúdo visível da janela rolando na tela quando o aplicativo estiver no modo de janela e o DWM estiver habilitado. Recomendamos que você não use as APIs ScrollWindow e ScrollWindowEx da GDI em seus aplicativos e, em vez disso, redesenhe seu conteúdo na tela em resposta à rolagem.

Use uma cadeia de permuta D3DSWAPEFFECT_FLIPEX por HWND

Os aplicativos que usam o Flip Model não devem usar várias cadeias de permuta do Flip Model direcionadas ao mesmo HWND.

Sincronização de quadros de aplicativos Direct3D 9Ex Flip Model

As estatísticas atuais são informações de temporização de quadros que os aplicativos de mídia usam para sincronizar fluxos de vídeo e áudio e recuperar de falhas de reprodução de vídeo. Para habilitar a disponibilidade de estatísticas atuais, o aplicativo Direct3D 9Ex deve garantir que o parâmetro BehaviorFlags que o aplicativo passa para IDirect3D9Ex::CreateDeviceEx contenha o sinalizador de comportamento de dispositivo D3DCREATE_ENABLE_PRESENTSTATS.

Por conveniência, a sintaxe do IDirect3D9Ex::CreateDeviceEx é repetida aqui.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);

O Direct3D 9Ex Flip Model adiciona o sinalizador de apresentação D3DPRESENT_FORCEIMMEDIATE que impõe o D3DPRESENT_INTERVAL_IMMEDIATE comportamento do sinalizador de apresentação. O aplicativo Direct3D 9Ex especifica esses sinalizadores de apresentação no parâmetro dwFlags que o aplicativo passa para IDirect3DDevice9Ex::P resentEx, conforme mostrado aqui.

HRESULT PresentEx(
  CONST RECT *pSourceRect,
  CONST RECT *pDestRect,
  HWND hDestWindowOverride,
  CONST RGNDATA *pDirtyRegion,
  DWORD dwFlags
);

Ao modificar seu aplicativo Direct3D 9Ex para Windows 7, você deve considerar as seguintes informações sobre os sinalizadores de apresentação D3DPRESENT especificados:

D3DPRESENT_DONOTFLIP

Este sinalizador está disponível apenas no modo de ecrã inteiro ou

(Apenas Windows 7)

quando o aplicativo define o SwapEffect membro do D3DPRESENT_PARAMETERS para D3DSWAPEFFECT_FLIPEX em uma chamada para CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Apenas Windows 7)

Esse sinalizador pode ser especificado somente se o aplicativo definir o SwapEffect membro do D3DPRESENT_PARAMETERS para D3DSWAPEFFECT_FLIPEX em uma chamada para CreateDeviceEx. O aplicativo pode usar esse sinalizador para atualizar imediatamente uma superfície com vários quadros posteriormente na fila DWM Present, essencialmente ignorando quadros intermediários.

Os aplicativos habilitados para FlipEx em janela podem usar esse sinalizador para atualizar imediatamente uma superfície com um quadro que está mais tarde na fila DWM Present, ignorando quadros intermediários. Isso é especialmente útil para aplicativos de mídia que desejam descartar quadros que foram detetados como tardios e apresentar quadros subsequentes no momento da composição. IDirect3DDevice9Ex::P resentEx retorna erro de parâmetro inválido se esse sinalizador for especificado incorretamente.

Para obter informações estatísticas atuais, o aplicativo obtém a estrutura D3DPRESENTSTATS chamando a IDirect3DSwapChain9Ex::GetPresentStatistics API.

A estrutura D3DPRESENTSTATS contém estatísticas sobre IDirect3DDevice9Ex::P resentEx chamadas. O dispositivo deve ser criado usando um IDirect3D9Ex::CreateDeviceEx chamada com o sinalizador D3DCREATE_ENABLE_PRESENTSTATS. Caso contrário, os dados retornados por GetPresentStatistics serão indefinidos. Uma cadeia de permuta Direct3D 9Ex habilitada para Flip-Model fornece informações estatísticas presentes nos modos de janela e tela cheia.

Para cadeias de permuta Direct3D 9Ex habilitadas para modelo Blt no modo de janela, todos os valores de estrutura D3DPRESENTSTATS serão zeros.

Para estatísticas presentes do FlipEx, GetPresentStatistics retorna D3DERR_PRESENT_STATISTICS_DISJOINT nas seguintes situações:

  • A primeira chamada para GetPresentStatistics sempre, o que indica o início de uma sequência
  • DWM transição de ligado para desligado
  • Mudança de modo: modo de janela de ou para transições de tela cheia ou tela cheia para tela cheia

Por conveniência, a sintaxe do GetPresentStatistics é repetida aqui.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

O método IDirect3DSwapChain9Ex::GetLastPresentCount retorna o último PresentCount, ou seja, a ID Presente da última chamada Present bem-sucedida feita por um dispositivo de exibição associado à cadeia de permuta. Este ID Presente é o valor do PresentCount membro da estrutura D3DPRESENTSTATS. Para cadeias de permuta Direct3D 9Ex habilitadas para modelo Blt, enquanto no modo de janela, todos os valores de estrutura D3DPRESENTSTATS serão zeros.

Por conveniência, a sintaxe de IDirect3DSwapChain9Ex::GetLastPresentCount é repetida aqui.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Quando você modifica seu aplicativo Direct3D 9Ex para Windows 7, você deve considerar as seguintes informações sobre a estrutura D3DPRESENTSTATS:

  • O valor PresentCount que GetLastPresentCount retorna não é atualizado quando uma chamada PresentEx com D3DPRESENT_DONOTWAIT especificado no parâmetro dwFlags retorna falha.
  • Quando PresentEx é chamado com D3DPRESENT_DONOTFLIP, uma chamada de GetPresentStatistics é bem-sucedida, mas não retorna uma estrutura de D3DPRESENTSTATS atualizada quando o aplicativo está no modo de janela.
  • PresentRefreshCount versus SyncRefreshCount em D3DPRESENTSTATS:
    • PresentRefreshCount é igual a SyncRefreshCount quando o aplicativo é apresentado em cada vsync.
    • SyncRefreshCount é obtido no intervalo vsync quando o presente foi enviado, SyncQPCTime é aproximadamente o tempo associado ao intervalo vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Sincronização de quadros para aplicativos em janela quando o DWM está desativado

Quando o DWM está desativado, os aplicativos em janela são exibidos diretamente na tela do monitor sem passar por uma cadeia invertida. No Windows Vista, não há suporte para obter informações de estatísticas de quadros para aplicativos em janela quando o DWM está desativado. Para manter uma API em que os aplicativos não precisam estar cientes de DWM, o Windows 7 retornará informações de estatísticas de quadro para aplicativos em janela quando o DWM estiver desativado. As estatísticas de quadro retornadas quando o DWM está desativado são apenas estimativas.

Walk-Through de um modelo Direct3D 9Ex Flip e apresentar amostra de estatísticas

Para optar pela apresentação FlipEx para Direct3D 9Ex de exemplo

  1. Verifique se o aplicativo de exemplo está sendo executado no Windows 7 ou versão posterior do sistema operacional.
  2. Defina o SwapEffect membro do D3DPRESENT_PARAMETERS para D3DSWAPEFFECT_FLIPEX em uma chamada para CreateDeviceEx.
    OSVERSIONINFO version;
    ZeroMemory(&version, sizeof(version));
    version.dwOSVersionInfoSize = sizeof(version);
    GetVersionEx(&version);
    
    // Sample would run only on Win7 or higher
    // Flip Model present and its associated present statistics behavior are only available on Windows 7 or higher operating system
    bool bIsWin7 = (version.dwMajorVersion > 6) || 
        ((version.dwMajorVersion == 6) && (version.dwMinorVersion >= 1));

    if (!bIsWin7)
    {
        MessageBox(NULL, L"This sample requires Windows 7 or higher", NULL, MB_OK);
        return 0;
    }

Para também optar pelo exemplo Present Statistics for Direct3D 9Ex associado ao FlipEx

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));

    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_FLIPEX;        // Opts into Flip Model present for D3D9Ex swapchain
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = 256;                
    d3dpp.BackBufferHeight = 256;
    d3dpp.BackBufferCount = QUEUE_SIZE;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

    g_iWidth = d3dpp.BackBufferWidth;
    g_iHeight = d3dpp.BackBufferHeight;

    // Create the D3DDevice with present statistics enabled - set D3DCREATE_ENABLE_PRESENTSTATS for behaviorFlags parameter
    if(FAILED(g_pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_ENABLE_PRESENTSTATS,
                                      &d3dpp, NULL, &g_pd3dDevice)))
    {
        return E_FAIL;
    }

Para evitar, detetar e recuperar de falhas

  1. Fila de chamadas presentes: a contagem de backbuffer recomendada é de 2 a 4.

  2. O exemplo Direct3D 9Ex adiciona um backbuffer implícito, o comprimento real da fila atual é a contagem de backbuffer + 1.

  3. Criar auxiliar Apresentar estrutura de fila para armazenar toda a ID Presente do Presente enviada com êxito (PresentCount) e PresentRefreshCount associada, calculada/esperada.

  4. Para detetar a ocorrência de falhas:

    • Ligue GetPresentStatistics.
    • Obtenha a ID atual (PresentCount) e a contagem de vsync onde o quadro é mostrado (PresentRefreshCount) do quadro cujas estatísticas atuais são obtidas.
    • Recupere o PresentRefreshCount esperado (TargetRefresh no código de exemplo) associado à ID Presente.
    • Se PresentRefreshCount real for posterior ao esperado, ocorreu uma falha.
  5. Para recuperar de uma falha:

    • Calcule quantos quadros ignorar (g_ variável iImmediates no código de exemplo).
    • Apresente os quadros ignorados com intervalo D3DPRESENT_FORCEIMMEDIATE.

Considerações para deteção de falhas e recuperação

  1. A recuperação de falha leva o número N (variável g_iQueueDelay no código de exemplo) de chamadas Present, onde N (g_iQueueDelay) é igual a g_iImmediates mais comprimento da fila Present, ou seja:

    • Pular quadros com o intervalo Presente D3DPRESENT_FORCEIMMEDIATE, além de
    • Presentes em fila que precisam ser processados
  2. Defina um limite para o comprimento da falha (GLITCH_RECOVERY_LIMIT na amostra). Se o aplicativo de exemplo não puder se recuperar de uma falha muito longa (ou seja, 1 segundo ou 60 vsyncs no monitor de 60Hz), pule sobre a animação intermitente e redefina a fila auxiliar Apresentar.

VOID Render()
{
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    g_pd3dDevice->BeginScene();

    // Compute new animation parameters for time and frame based animations

    // Time-based is a difference between base and current SyncRefreshCount
    g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
    // Frame-based is incrementing frame value
    g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;

    RenderBlurredMesh(TRUE);    // Time-based
    RenderBlurredMesh(FALSE);   // Frame-based

    g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;

    DrawText();

    g_pd3dDevice->EndScene();

    // Performs glitch recovery if glitch was detected
    if (g_bGlitchRecovery && (g_iImmediates > 0))
    {
        // If we have present immediates queued as a result of glitch detected, issue forceimmediate Presents for glitch recovery 
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE);
        g_iImmediates--;
        g_iShowingGlitchRecovery = MESSAGE_SHOW;
    }
    // Otherwise, Present normally
    else
    {
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, 0);
    }

    // Add to helper Present queue: PresentID + expected present refresh count of last submitted Present
    UINT PresentCount;
    g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
    g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);
    
    // QueueDelay specifies # Present calls to be processed before another glitch recovery attempt
    if (g_iQueueDelay > 0)
    {
        g_iQueueDelay--;
    }

    if (g_bGlitchRecovery)
    {
        // Additional DONOTFLIP presents for frame conversions, which basically follows the same logic, but without rendering
        for (DWORD i = 0; i < g_iDoNotFlipNum; i++)
        {
            if (g_TargetRefreshCount != -1)
            {
                g_TargetRefreshCount++;
                g_iFrameNumber++;
                g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
                g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;
                g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;
            }
            
            if (g_iImmediates > 0)
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE | D3DPRESENT_DONOTFLIP);
                g_iImmediates--;
            }
            else
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTFLIP);
            }
            UINT PresentCount;
            g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
            g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);

            if (g_iQueueDelay > 0)
            {
                g_iQueueDelay--;
            }
        }
    }

    // Check Present Stats info for glitch detection 
    D3DPRESENTSTATS PresentStats;

    // Obtain present statistics information for successfully displayed presents
    HRESULT hr = g_pd3dSwapChain->GetPresentStats(&PresentStats);

    if (SUCCEEDED(hr))
    {
        // Time-based update
        g_LastSyncRefreshCount = PresentStats.SyncRefreshCount;
        if ((g_SyncRefreshCount == -1) && (PresentStats.PresentCount != 0))
        {
            // First time SyncRefreshCount is reported, use it as base
            g_SyncRefreshCount = PresentStats.SyncRefreshCount;
        }

        // Fetch frame from the queue...
        UINT TargetRefresh = g_Queue.DequeueFrame(PresentStats.PresentCount);

        // If PresentStats returned a really old frame that we no longer have in the queue, just don't do any glitch detection
        if (TargetRefresh == FRAME_NOT_FOUND)
            return;

        if (g_TargetRefreshCount == -1)
        {
            // This is first time issued frame is confirmed by present stats, so fill target refresh count for all frames in the queue
            g_TargetRefreshCount = g_Queue.FillRefreshCounts(PresentStats.PresentCount, g_SyncRefreshCount);
        } 
        else
        {
            g_TargetRefreshCount++;
            g_iFrameNumber++;

            // To determine whether we're glitching, see if our estimated refresh count is confirmed
            // if the frame is displayed later than the expected vsync count
            if (TargetRefresh < PresentStats.PresentRefreshCount)
            {
                // then, glitch is detected!

                // If glitch is too big, don't bother recovering from it, just jump animation
                if ((PresentStats.PresentRefreshCount - TargetRefresh) > GLITCH_RECOVERY_LIMIT)
                {
                    g_iStartFrame += PresentStats.SyncRefreshCount - g_SyncRefreshCount;
                    ResetAnimation();
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;    
                } 
                // Otherwise, compute number of immediate presents to recover from it -- if we?re not still trying to recover from another glitch
                else if (g_iQueueDelay == 0)
                {
                      // skip frames to catch up to expected refresh count
                    g_iImmediates = PresentStats.PresentRefreshCount - TargetRefresh;
                    // QueueDelay specifies # Present calls before another glitch recovery 
                    g_iQueueDelay = g_iImmediates + QUEUE_SIZE;
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;
                }
            }
            else
            {
                // No glitch, reset glitch count
                g_iGlitchesInaRow = 0;
            }
        }
    }
    else if (hr == D3DERR_PRESENT_STATISTICS_DISJOINT)
    {
        // D3DERR_PRESENT_STATISTICS_DISJOINT means measurements should be started from the scratch (could be caused by mode change or DWM on/off transition)
        ResetAnimation();
    }

    // If we got too many glitches in a row, reduce framerate conversion factor (that is, render less frames)
    if (g_iGlitchesInaRow == FRAMECONVERSION_GLITCH_LIMIT)
    {
        if (g_iDoNotFlipNum < FRAMECONVERSION_LIMIT)
        {
            g_iDoNotFlipNum++;
        }
        g_iGlitchesInaRow = 0;
        g_iShowingDoNotFlipBump = MESSAGE_SHOW;
    }
}

Exemplo de cenário

  • A ilustração a seguir mostra um aplicativo com contagem de backbuffer de 4. O tamanho real da fila Presente é, portanto, 5.

    ilustração de um aplicativo renderizou quadros e apresenta fila

    O quadro A é direcionado para ir para a tela na contagem de intervalo de sincronização de 1, mas foi detetado que ele foi mostrado na contagem de intervalo de sincronização de 4. Portanto, ocorreu uma falha. Os 3 quadros subsequentes são apresentados com D3DPRESENT_INTERVAL_FORCEIMMEDIATE. A falha deve levar um total de 8 chamadas Present antes de ser recuperada - o próximo quadro será mostrado de acordo com sua contagem de intervalo de sincronização direcionada.

Resumo das recomendações de programação para sincronização de quadros

  • Crie uma lista de backup de todos os IDs LastPresentCount (obtidos por meio de GetLastPresentCount) e PresentRefreshCount estimado associado de todos os Presents enviados.

    Observação

    Quando o aplicativo chama PresentEx com D3DPRESENT_DONOTFLIP, a chamadaGetPresentStatisticsé bem-sucedida, mas não retorna uma estrutura de D3DPRESENTSTATS atualizada quando o aplicativo está no modo de janela.

  • Chame GetPresentStatistics para obter o PresentRefreshCount real associado a cada ID Presente de quadros mostrados, para garantir que o aplicativo manipule retornos de falha da chamada.

  • Se PresentRefreshCount real for posterior ao estimado PresentRefreshCount, uma falha será detetada. Compense enviando o Presente com D3DPRESENT_FORCEIMMEDIATE de quadros atrasados.

  • Quando um quadro é apresentado tardiamente na fila Presente, todos os quadros em fila subsequentes serão apresentados tardiamente. D3DPRESENT_FORCEIMMEDIATE corrigirá apenas o próximo quadro a ser apresentado após todos os quadros enfileirados. Portanto, a fila Presente ou a contagem de backbuffer não deve ser muito longa -- portanto, há menos falhas de quadro para acompanhar. A contagem ideal de backbuffer é de 2 a 4.

  • Se PresentRefreshCount estimado for posterior ao PresentRefreshCount real, a limitação DWM pode ter ocorrido. São possíveis as seguintes soluções:

    • reduzindo o comprimento da fila Presente
    • reduzir os requisitos de memória da GPU com qualquer outro meio além de reduzir o comprimento da fila presente (ou seja, diminuir a qualidade, remover efeitos e assim por diante)
    • especificando DwmEnableMMCSS para evitar a limitação de DWM em geral
  • Verifique a funcionalidade de exibição do aplicativo e o desempenho das estatísticas de quadro nos seguintes cenários:

    • com DWM ligado e desligado
    • Modos exclusivos e com janelas em tela cheia
    • hardware de menor capacidade
  • Quando os aplicativos não podem se recuperar de um grande número de quadros com falha com o D3DPRESENT_FORCEIMMEDIATE Present, eles podem executar as seguintes operações:

    • reduza o uso de CPU e GPU renderizando com menos carga de trabalho.
    • no caso de decodificação de vídeo, decodificar mais rápido, reduzindo a qualidade e, portanto, o uso de CPU e GPU.

Conclusão sobre as melhorias do Direct3D 9Ex

No Windows 7, os aplicativos que exibem vídeo ou medem a taxa de quadros durante a apresentação podem optar pelo Flip Model. As atuais melhorias nas estatísticas associadas ao Flip Model Direct3D 9Ex podem beneficiar aplicativos que sincronizam a apresentação por taxa de quadros, com feedback em tempo real para deteção e recuperação de falhas. Os desenvolvedores que adotam o Direct3D 9Ex Flip Model devem levar em conta a segmentação de um HWND separado do conteúdo GDI e a sincronização da taxa de quadros. Consulte os detalhes neste tópico. Para obter documentação adicional, consulte DirectX Developer Center no MSDN.

Apelo à ação

Recomendamos que você use o Direct3D 9Ex Flip Model e suas estatísticas atuais no Windows 7 ao criar aplicativos que tentam sincronizar a taxa de quadros da apresentação ou recuperar de falhas de exibição.

DirectX Developer Center no MSDN