Compartir a través de


Mejoras de Direct3D 9Ex

En este tema se describe la compatibilidad agregada de Windows 7 para la presentación en modo de giro y sus estadísticas actuales asociadas en Direct3D 9Ex y Desktop Window Manager. Las aplicaciones de destino incluyen aplicaciones de presentación basadas en velocidad de fotogramas o vídeo. Las aplicaciones que usan la presentación en modo de giro de Direct3D 9Ex reducen la carga de recursos del sistema cuando DWM está habilitado. Las mejoras de estadísticas de presentación asociadas con la presentación en modo de giro permiten a las aplicaciones Direct3D 9Ex controlar mejor la tasa de presentación proporcionando mecanismos de corrección y comentarios en tiempo real. Se incluyen explicaciones detalladas y punteros a los recursos de ejemplo.

En este tema se incluyen las siguientes secciones.

Mejoras de Direct3D 9Ex para Windows 7

La presentación en modo de giro de Direct3D 9Ex es un modo mejorado de presentar imágenes en Direct3D 9Ex que entrega de forma eficaz imágenes representadas a Windows 7 Desktop Window Manager (DWM) para la composición. A partir de Windows Vista, DWM compone todo el escritorio. Cuando DWM está habilitado, las aplicaciones en modo de ventana presentan su contenido en el escritorio mediante un método denominado Presentación en modo Blt para DWM (o modelo Blt). Con el modelo Blt, DWM mantiene una copia de la superficie representada de Direct3D 9Ex para la composición de escritorio. Cuando la aplicación se actualiza, el nuevo contenido se copia en la superficie DWM a través de un blt. En el caso de las aplicaciones que contienen contenido de Direct3D y GDI, los datos de GDI también se copian en la superficie DWM.

Disponible en Windows 7, la presentación en modo de giro en DWM (o modelo de giro) es un nuevo método de presentación que básicamente permite pasar identificadores de superficies de aplicación entre aplicaciones en modo ventana y DWM. Además de guardar recursos, el modelo de giro admite estadísticas actuales mejoradas.

Las estadísticas de presentación son información de tiempo de fotogramas que las aplicaciones pueden usar para sincronizar secuencias de vídeo y audio y recuperarse de errores de reproducción de vídeo. La información de tiempo de fotogramas de las estadísticas de presentación permite a las aplicaciones ajustar la velocidad de presentación de sus fotogramas de vídeo para una presentación más fluida. En Windows Vista, donde DWM mantiene una copia correspondiente de la superficie de marco para la composición de escritorio, las aplicaciones pueden usar las estadísticas de presentación proporcionadas por DWM. Este método para obtener las estadísticas de presentación seguirá estando disponible en Windows 7 para las aplicaciones existentes.

En Windows 7, las aplicaciones basadas en Direct3D 9Ex que adoptan el modelo de giro deben usar las API D3D9Ex para obtener las estadísticas de presentación. Cuando DWM está habilitado, las aplicaciones Direct3D 9Ex en modo de ventana y modo exclusivo de pantalla completa pueden esperar la misma información de estadísticas de presentación al usar el modelo de giro. Las estadísticas de presentación del modo de giro de Direct3D 9Ex permiten a las aplicaciones consultar estadísticas de presentación en tiempo real, en lugar de hacerlo después de que el fotograma se haya mostrado en pantalla; la misma información de estadísticas de presentación está disponible para las aplicaciones habilitadas para el modelo de giro en modo ventana como aplicaciones a pantalla completa; una marca agregada en las API de D3D9Ex permite a las aplicaciones de modelo de giro descartar eficazmente los fotogramas en tiempo de presentación.

El modelo de giro de Direct3D 9Ex debe usarse en nuevas aplicaciones de presentación basadas en velocidad de fotogramas o vídeo que tienen como destino Windows 7. Debido a la sincronización entre DWM y el tiempo de ejecución de Direct3D 9Ex, las aplicaciones que usan el modelo de giro deben especificar entre 2 y 4 búferes de retroceso para garantizar una presentación fluida. Las aplicaciones que usan la información de estadísticas de presentación se beneficiarán de las mejoras de las estadísticas de presentación habilitadas para el modelo de giro.

Presentación en modo de giro de Direct3D 9EX

Las mejoras de rendimiento de presentación en modo de giro de Direct3D 9Ex son significativas en el sistema cuando DWM está activado y cuando la aplicación está en modo de ventana, en lugar de en modo exclusivo de pantalla completa. En la siguiente tabla e ilustración se muestra una comparación simplificada de los usos de ancho de banda de memoria y lecturas y escrituras del sistema de aplicaciones con ventanas que eligen el modelo de giro frente al modelo Blt de uso predeterminado.

Presentación en modo Blt para DWM Presentación en modo de giro de D3D9Ex para DWM
1. La aplicación actualiza su marco (escritura)
1. La aplicación actualiza su marco (escritura)
2. El tiempo de ejecución de Direct3D copia el contenido de la superficie en una superficie de redirección de DWM (lectura, escritura)
2. El tiempo de ejecución de Direct3D pasa la superficie de la aplicación a DWM
3. Una vez completada la copia de superficie compartida, DWM representa la superficie de la aplicación en pantalla (lectura, escritura)
3. DWM representa la superficie de la aplicación en pantalla (lectura, escritura)

Ilustración de una comparación del modelo blt y el modelo de giro

La presentación en modo de giro reduce el uso de memoria del sistema al reducir el número de lecturas y escrituras por el tiempo de ejecución de Direct3D para la composición de fotogramas con ventanas por DWM. Esto reduce el consumo de energía del sistema y el uso general de memoria.

Las aplicaciones pueden aprovechar las mejoras de las estadísticas de presentación en modo de giro de Direct3D 9Ex cuando DWM está activado, independientemente de si la aplicación está en modo de ventana o en modo exclusivo de pantalla completa.

Modelo de programación y API

Las nuevas aplicaciones de velocidad de fotogramas o vídeo que usan las API de Direct3D 9Ex en Windows 7 pueden aprovechar las ventajas de la memoria y el ahorro de energía y de la presentación mejorada que ofrece la presentación en modo de giro cuando se ejecuta en Windows 7. (Cuando se ejecuta en versiones anteriores de Windows, el entorno de ejecución de Direct3D tiene como valor predeterminado para la aplicación la presentación en modo Blt).

La presentación en modo de giro implica que la aplicación puede aprovechar los mecanismos de corrección y comentarios de estadísticas de presentación en tiempo real cuando DWM está activado. Sin embargo, las aplicaciones que usan la presentación en modo de giro deben tener en cuenta las limitaciones cuando usan la representación simultánea de la API de GDI.

Puede modificar las aplicaciones existentes para aprovechar las ventajas de la presentación en modo de giro, con las mismas ventajas y advertencias que las aplicaciones recién desarrolladas.

Cómo incluir el modelo de giro de Direct3D 9Ex

Las aplicaciones de Direct3D 9Ex que tienen como destino Windows 7 pueden incluir el modelo de giro mediante la creación de la cadena de intercambio con el valor de enumeración D3DSWAPEFFECT_FLIPEX. Para incluir el modelo de giro, las aplicaciones especifican la estructura D3DPRESENT_PARAMETERS y, a continuación, pasan un puntero a esta estructura cuando llaman a la API IDirect3D9Ex::CreateDeviceEx. En esta sección se describe cómo las aplicaciones que tienen como destino Windows 7 usan IDirect3D9Ex::CreateDeviceEx para incluir el modelo de giro. Para obtener más información sobre la API IDirect3D9Ex::CreateDeviceEx, consulte IDirect3D9Ex::CreateDeviceEx en MSDN.

Para mayor comodidad, la sintaxis de D3DPRESENT_PARAMETERS e IDirect3D9Ex::CreateDeviceEx se repite aquí.

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;

Al modificar las aplicaciones de Direct3D 9Ex para Windows 7 para incluir el modelo de giro, debe tener en cuenta los siguientes elementos sobre los miembros especificados de D3DPRESENT_PARAMETERS:

BackBufferCount

(Solo Windows 7)

Cuando SwapEffect se establece en el nuevo tipo de efecto de cadena de intercambio de D3DSWAPEFFECT_FLIPEX, el número de búferes de reserva debe ser igual o mayor que 2, para evitar una penalización de rendimiento de la aplicación como resultado de esperar a que DWM libere el búfer de presentación anterior.

Cuando la aplicación también usa estadísticas de presentación asociadas con D3DSWAPEFFECT_FLIPEX, se recomienda establecer el número de búferes de reserva de 2 a 4.

El uso de D3DSWAPEFFECT_FLIPEX en Windows Vista o versiones anteriores del sistema operativo devolverá un error de CreateDeviceEx.

SwapEffect

(Solo Windows 7)

El nuevo tipo de efecto de cadena de intercambio D3DSWAPEFFECT_FLIPEX designa cuándo una aplicación adopta la presentación en modo de giro para DWM. Permite que la aplicación use más eficazmente la memoria y la potencia, y también permite a la aplicación aprovechar las estadísticas de presentación en pantalla completa en modo de ventana. El comportamiento de la aplicación de pantalla completa no se ve afectado. Si el modo de ventanas se establece en TRUE y SwapEffect se establece en D3DSWAPEFFECT_FLIPEX, el tiempo de ejecución crea un búfer de retroceso adicional y gira el identificador que pertenece al búfer que se convierte en el búfer frontal en el momento de la presentación.

Flags

(Solo Windows 7)

No se puede establecer la marca D3DPRESENTFLAG_LOCKABLE_BACKBUFFER si SwapEffect se establece en el nuevo tipo de efecto de cadena de intercambio D3DSWAPEFFECT_FLIPEX.

Directrices de diseño para aplicaciones de modelo de giro de Direct3D 9Ex

Use las instrucciones de las secciones siguientes para diseñar las aplicaciones de modelo de giro de Direct3D 9Ex.

Uso de la presentación en modo de giro en un HWND independiente a partir de la presentación en modo Blt

Las aplicaciones deben utilizar la presentación en modo de giro de Direct3D 9Ex en un HWND que no sea también el destino de otras API, incluida la presentación en modo Blt de Direct3D 9Ex, otras versiones de Direct3D, o GDI. La presentación en modo de giro se puede usar para presentar a las ventanas secundarias; es decir, las aplicaciones pueden usar el modelo de giro cuando no se mezcle con el modelo de Blt en el mismo HWND, como se muestra en las ilustraciones siguientes.

Ilustración de la ventana primaria de Direct3d y una ventana secundaria de GDi, cada una con su propio HWND

Ilustración de la ventana primaria de GDI y una ventana secundaria de Direct3d, cada una con su propio HWND

Dado que modelo Blt mantiene una copia adicional de la superficie, GDI y otro contenido de Direct3D se pueden agregar al mismo HWND a través de actualizaciones por etapas de Direct3D y GDI. Con el modelo de giro, solo el contenido de Direct3D 9Ex en cadenas de intercambio D3DSWAPEFFECT_FLIPEX que se pasan a DWM estará visible. Todas las demás actualizaciones de contenido del modelo Blt de Direct3D o GDI se omitirán, como se muestra en las ilustraciones siguientes.

Ilustración del texto de GDI que podría no mostrarse si se usa el modelo de giro y el contenido de Ddirect3d y GDI están en el mismo HWND

Ilustración del contenido de Direct3d y GDI en el que dwm está habilitado y la aplicación está en modo de ventana

Por lo tanto, el modelo de giro debe estar habilitado para superficies de búferes de cadena de intercambio en las que el modelo de giro de Direct3D 9Ex solo se representa en todo el HWND.

No usar el modelo de giro con ScrollWindow o ScrollWindowEx de GDI

Algunas aplicaciones de direct3D 9Ex usan las funciones ScrollWindow o ScrollWindowEx de GDI para actualizar el contenido de la ventana cuando se desencadena un evento de desplazamiento del usuario. ScrollWindow y ScrollWindowEx realizan blts de contenido de ventana en pantalla a medida que se desplaza una ventana. Estas funciones también requieren actualizaciones del modelo Blt para el contenido de GDI y Direct3D 9Ex. Las aplicaciones que usan cualquiera de las funciones no mostrarán necesariamente el contenido visible de la ventana que se desplaza en pantalla cuando la aplicación está en modo de ventana y DWM está habilitado. Se recomienda no usar las API ScrollWindow y ScrollWindowEx de GDI en las aplicaciones y, en su lugar, volver a dibujar su contenido en la pantalla en respuesta al desplazamiento.

Uso de una cadena de intercambio de D3DSWAPEFFECT_FLIPEX por HWND

Las aplicaciones que usan el modelo de giro no deben usar varias cadenas de intercambio del modelo de giro destinadas al mismo HWND.

Sincronización de fotogramas de aplicaciones de modelos de giro de Direct3D 9Ex

Las estadísticas de presentación son información de tiempo de fotogramas que las aplicaciones multimedia usan para sincronizar secuencias de vídeo y audio y recuperarse de errores de reproducción de vídeo. Para habilitar la disponibilidad de las estadísticas de presentación, la aplicación Direct3D 9Ex debe asegurarse de que el parámetro BehaviorFlags que la aplicación pasa a IDirect3D9Ex::CreateDeviceEx contiene la marca de comportamiento del dispositivo D3DCREATE_ENABLE_PRESENTSTATS.

Para mayor comodidad, la sintaxis de IDirect3D9Ex::CreateDeviceEx se repite aquí.

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

El modelo de giro de Direct3D 9Ex agrega la marca de presentación D3DPRESENT_FORCEIMMEDIATE, que aplica el comportamiento de la marca de presentación D3DPRESENT_INTERVAL_IMMEDIATE. La aplicación Direct3D 9Ex especifica estas marcas de presentación en el parámetro dwFlags que la aplicación pasa a IDirect3DDevice9Ex::PresentEx, como se muestra aquí.

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

Al modificar la aplicación Direct3D 9Ex para Windows 7, debe tener en cuenta la siguiente información sobre las marcas de presentación de D3DPRESENT especificadas:

D3DPRESENT_DONOTFLIP

Esta marca solo está disponible en modo de pantalla completa o

(Solo Windows 7)

cuando la aplicación establece el miembro SwapEffect de D3DPRESENT_PARAMETERS en D3DSWAPEFFECT_FLIPEX en una llamada a CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Solo Windows 7)

Esta marca solo se puede especificar si la aplicación establece el miembro SwapEffect de D3DPRESENT_PARAMETERS en D3DSWAPEFFECT_FLIPEX en una llamada a CreateDeviceEx. La aplicación puede usar esta marca para actualizar inmediatamente una superficie con varios fotogramas más adelante en la cola de presentación de DWM, básicamente omitiendo fotogramas intermedios.

Las aplicaciones habilitadas para FlipEx con ventanas pueden usar esta marca para actualizar inmediatamente una superficie con un marco que se encuentra más adelante en la cola de presentación de DWM, omitiendo fotogramas intermedios. Esto es especialmente útil para las aplicaciones multimedia que desean descartar fotogramas que se han detectado como tarde y presentar fotogramas posteriores en el momento de la composición. IDirect3DDevice9Ex::PresentEx devuelve un error de parámetro no válido si no se especifica correctamente esta marca.

Para obtener información de las estadísticas de presentación, la aplicación obtiene la estructura D3DPRESENTSTATS llamando a la API IDirect3DSwapChain9Ex::GetPresentStatistics.

La estructura D3DPRESENTSTATS contiene estadísticas sobre las llamadas a IDirect3DDevice9Ex::PresentEx. El dispositivo debe crearse mediante una llamada IDirect3D9Ex::CreateDeviceEx con la marca D3DCREATE_ENABLE_PRESENTSTATS. De lo contrario, los datos devueltos por GetPresentStatistics no estarán definidos. Una cadena de intercambio de Direct3D 9Ex habilitada para el modelo de giro proporciona información sobre las estadísticas de presentación tanto en modo de ventana como de pantalla completa.

En el caso de las cadenas de intercambio de Direct3D 9Ex habilitadas para el modelo Blt en modo de ventana, todos los valores de la estructura D3DPRESENTSTATS serán ceros.

Para las estadísticas de presentación de FlipEx, GetPresentStatistics devuelve D3DERR_PRESENT_STATISTICS_DISJOINT en las situaciones siguientes:

  • Primera llamada a GetPresentStatistics, que indica el principio de una secuencia
  • Transición de DWM de activado a desactivado
  • Cambio de modo: modo con ventana a o desde la pantalla completa o desde la pantalla completa a transiciones de pantalla completa

Para mayor comodidad, la sintaxis de GetPresentStatistics se repite aquí.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

El método IDirect3DSwapChain9Ex::GetLastPresentCount devuelve el último PresentCount, es decir, el identificador de presentación de la última llamada Present correcta realizada por un dispositivo de visualización asociado a la cadena de intercambio. Este ID de presentación es el valor del miembro PresentCount de la estructura D3DPRESENTSTATS. En el caso de las cadenas de intercambio de Direct3D 9Ex habilitadas para el modelo Blt en modo de ventana, todos los valores de la estructura D3DPRESENTSTATS serán ceros.

Para mayor comodidad, la sintaxis de IDirect3DSwapChain9Ex::GetLastPresentCount se repite aquí.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Al modificar la aplicación Direct3D 9Ex para Windows 7, debe tener en cuenta la siguiente información sobre la estructura D3DPRESENTSTATS:

  • El valor PresentCount que devuelve GetLastPresentCount no se actualiza cuando una llamada a PresentEx con D3DPRESENT_DONOTWAIT especificado en el parámetro dwFlags devuelve un error.
  • Cuando se llama a PresentEx con D3DPRESENT_DONOTFLIP, una llamada a GetPresentStatistics se realiza correctamente, pero no devuelve una estructura D3DPRESENTSTATS actualizada cuando la aplicación está en modo de ventana.
  • PresentRefreshCount frente a SyncRefreshCount en D3DPRESENTSTATS:
    • PresentRefreshCount es igual a SyncRefreshCount cuando la aplicación se presenta en cada vsync.
    • SyncRefreshCount se obtiene en el intervalo vsync cuando se envía la presentación, SyncQPCTime es aproximadamente el tiempo asociado al intervalo vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Sincronización de fotogramas para aplicaciones con ventanas cuando DWM está desactivado

Cuando DWM está desactivado, las aplicaciones con ventana se muestran directamente en la pantalla del monitor sin pasar por una cadena de giro. En Windows Vista, no se admite la obtención de información de estadísticas de fotogramas para las aplicaciones con ventanas cuando DWM está desactivado. Para mantener una API en la que las aplicaciones no necesitan ser compatibles con DWM, Windows 7 devolverá información de estadísticas de fotogramas para las aplicaciones con ventanas cuando DWM está desactivado. Las estadísticas de fotogramas que se devuelven cuando DWM está desactivado son solo estimaciones.

Tutorial de una muestra de estadísticas de presentación y modelo de giro de Direct3D 9Ex

Para incluir la presentación de FlipEx para el ejemplo de Direct3D 9Ex

  1. Asegúrese de que la aplicación de ejemplo se ejecuta en Windows 7 o una versión posterior del sistema operativo.
  2. Establezca el miembro SwapEffect de D3DPRESENT_PARAMETERS en D3DSWAPEFFECT_FLIPEX en una llamada a 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 incluir también el ejemplo de estadísticas de presentación asociado a FlipEx para Direct3D 9Ex

    // 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, detectar y recuperarse de problemas

  1. Ponga en cola las llamadas de presentación: el recuento de búferes de reserva recomendado es de 2 a 4.

  2. El ejemplo de Direct3D 9Ex agrega un búfer de reserva implícito, la longitud real de la cola de presentaciones es el recuento de búferes de reserva + 1.

  3. Cree una estructura de cola de presentaciones auxiliar para almacenar todos los identificadores de presentación enviados y asociados correctamente, además del PresentRefreshCount calculado/esperado.

  4. Para detectar la aparición de errores:

    • Llame a GetPresentStatistics.
    • Obtenga el identificador de presentación (PresentCount) y el recuento de vsync donde se muestra el fotograma (PresentRefreshCount) del fotograma cuyas estadísticas de presentación se obtienen.
    • Recupere el PresentRefreshCount esperado (TargetRefresh en el código de ejemplo) asociado al identificador de presentación.
    • Si PresentRefreshCount real es posterior a lo esperado, se ha producido un error.
  5. Para recuperarse de problemas:

    • Calcule el número de fotogramas que se van a omitir (variable g_ iImmediates en el código de ejemplo).
    • Presente los fotogramas omitidos con el intervalo D3DPRESENT_FORCEIMMEDIATE.

Consideraciones para la detección y recuperación de problemas

  1. La recuperación de problemas toma N (variable g_iQueueDelay en código de ejemplo) número de llamadas de presentación donde N (g_iQueueDelay) es igual a g_iImmediates más la longitud de la cola de presentaciones, es decir:

    • Se omiten los fotogramas con D3DPRESENT_FORCEIMMEDIATE de intervalo de presentaciones, además de
    • Las presentaciones que deben procesarse se ponen en cola
  2. Establezca un límite en la longitud del error (GLITCH_RECOVERY_LIMIT en la muestra). Si la aplicación de ejemplo no puede recuperarse de un error que es demasiado largo (es decir, 1 segundo o 60 vsyncs en un monitor de 60 Hz), salte por la animación intermitente y restablezca la cola del asistente de presentaciones.

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

Escenario de ejemplo

  • En la ilustración siguiente se muestra una aplicación con el recuento de 4 búferes. Por lo tanto, la longitud real de la cola de presentaciones es 5.

    Ilustración de una aplicación de fotogramas representados y cola de presentaciones

    El fotograma A está destinado a ir en pantalla en el recuento de intervalos de sincronización de 1, pero se detectó que se mostró en el recuento de intervalos de sincronización de 4. Por lo tanto, se ha producido un error. Los 3 fotogramas posteriores se presentan con D3DPRESENT_INTERVAL_FORCEIMMEDIATE. El error debe tardar un total de 8 llamadas de presentación antes de recuperarse: el siguiente fotograma se mostrará según su recuento de intervalos de sincronización de destino.

Resumen de recomendaciones de programación para la sincronización de fotogramas

  • Cree una lista de copia de seguridad de todos los identificadores LastPresentCount (obtenidos a través de GetLastPresentCount) y PresentRefreshCount estimado asociado de todos los elementos de presentaciones.

    Nota:

    Cuando la aplicación llama a PresentEx con D3DPRESENT_DONOTFLIP, la llamada GetPresentStatistics se realiza correctamente, pero no devuelve una estructura D3DPRESENTSTATS actualizada cuando la aplicación está en modo de ventana.

  • Llame a GetPresentStatistics para obtener el valor actual de PresentRefreshCount asociado a cada identificador actual de fotogramas que se muestra, para asegurarse de que la aplicación controla las devoluciones de error de la llamada.

  • Si PresentRefreshCount real es posterior a PresentRefreshCount estimado, se detecta un error. Compénselo enviando la presentación de fotogramas retrasados con D3DPRESENT_FORCEIMMEDIATE.

  • Cuando un fotograma se presenta tarde en la cola de presentaciones, todos los siguientes fotogramas de la cola se presentarán tarde. D3DPRESENT_FORCEIMMEDIATE corregirá solo el siguiente fotograma que se va a presentar después de todos los fotogramas en cola. Por lo tanto, el recuento de colas o búferes de presentación no debe ser demasiado largo, por lo que hay menos problemas de fotogramas con los que ponerse al día. El recuento óptimo del búfer de reserva es de 2 a 4.

  • Si PresentRefreshCount estimado es posterior a PresentRefreshCount real, es posible que se haya producido una limitación de DWM. Son posibles las siguientes soluciones:

    • reducir la longitud de la cola de presentaciones
    • reducir los requisitos de memoria de GPU con cualquier otro medio además de reducir la longitud de la cola de presentaciones (es decir, reducir la calidad, eliminar efectos, etc.)
    • especificar DwmEnableMMCSS para evitar la limitación de DWM en general
  • Compruebe la funcionalidad de visualización de la aplicación y el rendimiento de las estadísticas de fotogramas en los escenarios siguientes:

    • con DWM activado y desactivado
    • modos exclusivos y con ventanas de pantalla completa
    • hardware de funcionalidad inferior
  • Cuando las aplicaciones no se pueden recuperar de un gran número de fotogramas con presentación D3DPRESENT_FORCEIMMEDIATE, pueden realizar las siguientes operaciones:

    • reducir el uso de CPU y GPU mediante la representación con menos carga de trabajo.
    • en el caso de la descodificación de vídeo, descodifique más rápido reduciendo la calidad y, por lo tanto, el uso de CPU y GPU.

Conclusión sobre las mejoras de Direct3D 9Ex

En Windows 7, las aplicaciones que muestran la velocidad de fotogramas de vídeo o medidor durante la presentación pueden optar por el modelo de giro. Las mejoras en las estadísticas de presentación asociadas al modelo de giro de Direct3D 9Ex pueden beneficiar a las aplicaciones que sincronizan la presentación por velocidad de fotogramas, con comentarios en tiempo real para la detección y recuperación de errores. Los desarrolladores que adoptan el modelo de giro de Direct3D 9Ex deben tener como destino un HWND independiente del contenido de GDI y la sincronización de velocidad de fotogramas en cuenta. Consulte los detalles de este tema. Para obtener documentación adicional, consulte Centro para desarrolladores de DirectX en MSDN.

Pasar a la acción

Le animamos a usar el modelo de giro de Direct3D 9Ex y sus estadísticas de presentaciones en Windows 7 al crear aplicaciones que intenten sincronizar la velocidad de fotogramas de presentación o para recuperarse de los problemas de visualización.

Centro para desarrolladores de DirectX en MSDN