Поделиться через


Улучшения в Direct3D 9Ex

В этом разделе описывается добавленная поддержка Режима переверки Windows 7 и связанная с ней статистика в Direct3D 9Ex и диспетчере окон рабочего стола. Целевые приложения включают приложения презентации на основе видео или кадров. Приложения, использующие режим переверки Direct3D 9Ex, снижают нагрузку системного ресурса при включении DWM. В настоящее время улучшения статистики, связанные с режимом flip Present, позволяют приложениям Direct3D 9Ex лучше управлять скоростью презентации, предоставляя механизмы обратной связи и исправления в режиме реального времени. Подробные объяснения и указатели на примеры ресурсов включены.

Эта тема описана в следующих разделах.

Усовершенствованные возможности Direct3D 9Ex для Windows 7

Представление режима переверки Direct3D 9Ex — это улучшенный режим представления изображений в Direct3D 9Ex, который эффективно передает отрисованные изображения в диспетчер окон рабочего стола Windows 7 (DWM) для композиции. Начиная с Windows Vista, DWM создает весь рабочий стол. Если DWM включен, приложения в режиме окна отображают содержимое на рабочем столе с помощью метода Blt Mode Present to DWM (или Blt Model). При использовании модели Blt DWM поддерживает копию отрисовки Direct3D 9Ex для композиции Desktop. При обновлении приложения новое содержимое копируется в область DWM через blt. Для приложений, содержащих содержимое Direct3D и GDI, данные GDI также копируются на поверхность DWM.

Доступно в Windows 7, режим перевернутого представления в DWM (или модель flip) — это новый метод презентации, который, по сути, позволяет передавать дескриптор поверхностей приложений между приложениями в режиме окна и DWM. Помимо экономии ресурсов, модель Flip поддерживает расширенную текущую статистику.

Текущая статистика — это сведения о времени кадров, которые приложения могут использовать для синхронизации видеопотоков и аудиопотоков и восстановления после сбоев воспроизведения видео. Сведения о времени кадров в текущей статистике позволяют приложениям настраивать частоту презентации своих видеокадров для более гладкой презентации. В Windows Vista, где DWM поддерживает соответствующую копию поверхности кадра для композиции рабочего стола, приложения могут использовать текущую статистику, предоставляемую DWM. Этот метод получения текущей статистики по-прежнему будет доступен в Windows 7 для существующих приложений.

В Windows 7 приложения на основе Direct3D 9Ex, которые принимают модель flip, должны использовать API D3D9Ex для получения текущей статистики. Если DWM включен, в окне и полноэкранном монопольном режиме приложения Direct3D 9Ex могут ожидать те же данные статистики при использовании модели Flip. Direct3D 9Ex Flip Model представляет статистику, которая позволяет приложениям запрашивать текущую статистику в режиме реального времени, а не после отображения кадра на экране; те же сведения о статистике доступны для приложений с поддержкой "Перевернутая модель" в режиме окна в виде полноэкранных приложений; добавленный флаг в API D3D9Ex позволяет приложениям модели flip эффективно удалять поздние кадры во время презентации.

Модель Direct3D 9Ex Flip должна использоваться новыми приложениями презентации на основе видео или кадров на основе частоты кадров, предназначенными для Windows 7. Из-за синхронизации между DWM и средой выполнения Direct3D 9Ex приложения, использующие модель Flip, должны указывать от 2 до 4 обратных заборов, чтобы обеспечить плавное представление. Эти приложения, использующие сведения о статистике, будут воспользоваться преимуществами использования модели flip, включаемой в настоящее время улучшения статистики.

Презентация режима переверки Direct3D 9EX

Улучшения производительности Direct3D 9Ex Flip Mode Present важны в системе, когда DWM включен и когда приложение находится в окне, а не в полноэкранном эксклюзивном режиме. В следующей таблице и иллюстрации показано упрощенное сравнение использования пропускной способности памяти и системных операций чтения и записи оконных приложений, которые выбирают модель Перевернуть и модель Blt по умолчанию.

Режим Blt, присутствующий в DWM Режим перевернутого представления D3D9Ex в DWM
1. Приложение обновляет кадр (запись)
1. Приложение обновляет кадр (запись)
2. Среда выполнения Direct3D копирует содержимое поверхности в область перенаправления DWM (чтение, запись)
2. Среда выполнения Direct3D передает область приложения в DWM
3. После завершения общей копии поверхности DWM отрисовывает область приложения на экране (чтение, запись)
3. DWM отображает область приложения на экране (чтение, запись)

иллюстрация сравнения модели blt и модели переверки

Режим переворачивания уменьшает использование памяти системы, уменьшая количество операций чтения и записи в среде выполнения Direct3D для композиции оконных кадров dwM. Это снижает потребление электроэнергии системы и общее использование памяти.

Приложения могут воспользоваться преимуществами Режима переверки Direct3D 9Ex, которые предоставляют улучшения статистики при включении DWM независимо от того, находится ли приложение в окне или в полноэкранном монопольном режиме.

Модель программирования и API

Новые приложения для просмотра скорости видео или кадров, использующие API Direct3D 9Ex в Windows 7, могут воспользоваться преимуществами памяти и экономии энергии и улучшенной презентации, предлагаемой режимом переверки при работе в Windows 7. (При выполнении в предыдущих версиях Windows среда выполнения Direct3D по умолчанию использует приложение в режиме Blt Present.)

Режим переворачивения предполагает, что приложение может воспользоваться преимуществами возможностей представления статистики и механизмов исправления в режиме реального времени при включении DWM. Однако приложения, использующие режим переворачивания, должны учитывать ограничения при использовании параллельной отрисовки API GDI.

Вы можете изменить существующие приложения, чтобы воспользоваться преимуществами режима переверки, с теми же преимуществами и предостережениями, что и недавно разработанные приложения.

Выбор модели Direct3D 9Ex Flip

Приложения Direct3D 9Ex, предназначенные для Windows 7, могут выбрать модель flip, создав цепочку буферов со значением перечисления D3DSWAPEFFECT_FLIPEX . Чтобы выбрать модель flip, приложения указывают структуру D3DPRESENT_PARAMETERS, а затем передайте указатель на эту структуру при вызове API IDirect3D9Ex::CreateDeviceEx. В этом разделе описывается, как приложения, предназначенные для Windows 7, используют IDirect3D9Ex::CreateDeviceEx , чтобы выбрать модель Flip. Дополнительные сведения об API IDirect3D9Ex::CreateDeviceEx см. в разделе IDirect3D9Ex::CreateDeviceEx на сайте MSDN.

Для удобства синтаксис D3DPRESENT_PARAMETERS и IDirect3D9Ex::CreateDeviceEx повторяется здесь.

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;

При изменении приложений Direct3D 9Ex для Windows 7, чтобы принять участие в модели flip, следует учитывать следующие элементы о указанных элементах D3DPRESENT_PARAMETERS:

BackBufferCount

(Только Для Windows 7)

Если параметр SwapEffect имеет новый тип эффекта цепочки буферов D3DSWAPEFFECT_FLIPEX, количество буферов обратного буфера должно быть равно или больше 2, чтобы предотвратить штраф производительности приложения в результате ожидания предыдущего буфера Текущего буфера, который будет выпущен DWM.

Если приложение также использует текущую статистику, связанную с D3DSWAPEFFECT_FLIPEX, рекомендуется задать значение от 2 до 4.

Использование D3DSWAPEFFECT_FLIPEX в Windows Vista или предыдущих версиях операционной системы приведет к сбою из CreateDeviceEx.

SwapEffect

(Только Для Windows 7)

Новый тип эффекта цепочки буферов D3DSWAPEFFECT_FLIPEX указывает, когда приложение принимает режим переворачивания в DWM. Это позволяет приложению более эффективно использовать память и мощность, а также позволяет приложению воспользоваться полноэкранной статистикой в окне. Поведение полноэкранного приложения не влияет. Если параметр Windowed имеет значение TRUE , а параметр SwapEffect имеет значение D3DSWAPEFFECT_FLIPEX, среда выполнения создает один дополнительный буфер задней части и поворачивает любой дескриптор, принадлежащий буферу, который становится передним буфером во время презентации.

Flags

(Только Для Windows 7)

Флаг D3DPRESENTFLAG_LOCKABLE_BACKBUFFER нельзя задать, если параметр SwapEffect имеет новый тип эффекта цепочки буферов D3DSWAPEFFECT_FLIPEX.

Рекомендации по проектированию приложений модели Direct3D 9Ex Flip

Используйте рекомендации в следующих разделах для разработки приложений Модели Direct3D 9Ex Flip.

Использование режима переверки в отдельном HWND из режима Blt

Приложения должны использовать режим переверки Direct3D 9Ex в HWND, который также не предназначен для других API, включая режим Blt Present Direct3D 9Ex, другие версии Direct3D или GDI. Режим переверки может использоваться для представления дочерних окон; То есть приложения могут использовать модель Flip, если она не смешана с моделью Blt в том же HWND, как показано на следующих рисунках.

иллюстрация родительского окна direct3d и дочернего окна gdi, каждая из которых имеет собственный hwnd

иллюстрация родительского окна gdi и дочернего окна direct3d, каждая из которых имеет собственный навесной

Так как модель Blt поддерживает дополнительную копию поверхности, GDI и другое содержимое Direct3D можно добавить в то же HWND с помощью фрагментных обновлений из Direct3D и GDI. С помощью модели переверки содержимое Direct3D 9Ex в цепочках буферов D3DSWAPEFFECT_FLIPEX, передаваемых в DWM, будет видно только содержимое Direct3D 9Ex. Все остальные обновления содержимого Blt Model Direct3D или GDI будут игнорироваться, как показано на следующих иллюстрациях.

Иллюстрация текста gdi, который может не отображаться, если модель переверки используется и direct3d и содержимое gdi находятся в одном и том же hwnd

иллюстрация содержимого direct3d и gdi, в котором включена dwm, и приложение находится в режиме окна

Таким образом, модель flip должна быть включена для буферов цепочки буферов, где модель Direct3D 9Ex Flip только отрисовывается во всем HWND.

Не используйте модель flip с прокруткой GDI ScrollWindow или ScrollWindowEx

Некоторые приложения Direct3D 9Ex используют функции GDI ScrollWindow или ScrollWindowEx для обновления содержимого окна при активации события прокрутки пользователя. ScrollWindow и ScrollWindowEx выполняют большие двоичные объекты содержимого окна на экране, так как окно прокручивается. Эти функции также требуют обновления модели Blt для содержимого GDI и Direct3D 9Ex. Приложения, использующие любую функцию, не обязательно будут отображать видимое содержимое окна, прокручиваемое на экране, когда приложение находится в режиме окна, и DWM включен. Рекомендуется не использовать API ScrollWindow и ScrollWindowEx GDI в приложениях, а вместо этого перерисовывать содержимое на экране в ответ на прокрутку.

Использование одной D3DSWAPEFFECT_FLIPEX цепочки буферов на HWND

Приложения, использующие модель Flip, не должны использовать несколько цепочек переключения модели flip, предназначенные для одного и того же HWND.

Синхронизация кадров приложений модели Direct3D 9Ex Flip

Текущая статистика — это сведения о времени кадра, используемые приложениями мультимедиа для синхронизации видео и аудиопотоков и восстановления после сбоев воспроизведения видео. Чтобы включить доступность статистики, приложение Direct3D 9Ex должно убедиться, что параметр BehaviorFlags, который приложение передает в IDirect3D9Ex::CreateDeviceEx, содержит флаг поведения устройства D3DCREATE_ENABLE_PRESENTSTATS.

Для удобства синтаксис IDirect3D9Ex::CreateDeviceEx повторяется здесь.

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

Direct3D 9Ex Flip Model добавляет флаг презентации D3DPRESENT_FORCEIMMEDIATE , который применяет поведение флага презентации D3DPRESENT_INTERVAL_IMMEDIATE презентации. Приложение Direct3D 9Ex указывает эти флаги презентации в параметре dwFlags, который приложение передает в IDirect3Device9Ex::P resentEx, как показано здесь.

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

При изменении приложения Direct3D 9Ex для Windows 7 следует учитывать следующие сведения о указанных флагах презентации D3DPRESENT :

D3DPRESENT_DONOTFLIP

Этот флаг доступен только в полноэкранном режиме или

(Только Для Windows 7)

Если приложение задает элемент SwapEffect D3DPRESENT_PARAMETERS D3DSWAPEFFECT_FLIPEX в вызове CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Только Для Windows 7)

Этот флаг можно указать, только если приложение задает член SwapEffect D3DPRESENT_PARAMETERS D3DSWAPEFFECT_FLIPEX в вызове CreateDeviceEx. Приложение может использовать этот флаг для немедленного обновления поверхности с несколькими кадрами позже в очереди DWM Present, в основном пропуская промежуточные кадры.

Окна в приложениях с поддержкой FlipEx могут использовать этот флаг для немедленного обновления поверхности с кадром, который позже в очереди DWM Present, пропуская промежуточные кадры. Это особенно полезно для приложений мультимедиа, которые хотят отменить кадры, обнаруженные как поздние и представленные последующие кадры во время композиции. IDirect3Device9Ex::P resentEx возвращает недопустимую ошибку параметра, если этот флаг неправильно указан.

Чтобы получить сведения о статистике, приложение получает структуру D3DPRESENTSTATS путем вызова API IDirect3DSwapChain9Ex::GetPresentStatistics.

Структура D3DPRESENTSTATS содержит статистику о вызовах IDirect3Device9Ex::P resentEx. Устройство должно быть создано с помощью вызова IDirect3D9Ex::CreateDeviceEx с флагом D3DCREATE_ENABLE_PRESENTSTATS. В противном случае данные, возвращаемые GetPresentStatistics , не определены. Цепочка буферов Direct3D 9Ex с поддержкой Flip-Model предоставляет сведения о статистике как в окнах, так и в полноэкранном режиме.

Для цепочек буферов Direct3D 9Ex с поддержкой Blt-Model все значения структуры D3DPRESENTSTATS будут нулями.

Для текущей статистики FlipEx GetPresentStatistics возвращает D3DERR_PRESENT_STATISTICS_DISJOINT в следующих ситуациях:

  • Первый вызов GetPresentStatistics когда-либо, указывающий начало последовательности
  • Переход DWM с выключения
  • Изменение режима: режим окна или с полноэкранного или полноэкранного перехода

Для удобства синтаксис GetPresentStatistics повторяется здесь.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

Метод IDirect3DSwapChain9Ex::GetLastPresentCount возвращает последнее значение PresentCount, то есть идентификатор текущего успешного вызова Present, который был выполнен устройством отображения, связанным с цепочкой буферов. Этот идентификатор представляет собой значение элемента PresentCount структуры D3DPRESENTSTATS . Для цепочек буферов Direct3D 9Ex с поддержкой Blt-Model все значения структуры D3DPRESENTSTATS будут нулями.

Для удобства синтаксис IDirect3DSwapChain9Ex::GetLastPresentCount повторяется здесь.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

При изменении приложения Direct3D 9Ex для Windows 7 следует учитывать следующие сведения о структуре D3DPRESENTSTATS:

  • Значение PresentCount, возвращаемое GetLastPresentCount, не обновляется при вызове PresentEx с D3DPRESENT_DONOTWAIT, указанным в параметре dwFlags, возвращает сбой.
  • При вызове PresentEx с D3DPRESENT_DONOTFLIP вызов GetPresentStatistics завершается успешно, но не возвращает обновленную структуру D3DPRESENTSTATS, когда приложение находится в окне.
  • PresentRefreshCount и SyncRefreshCount в D3DPRESENTSTATS:
    • PresentRefreshCount равно SyncRefreshCount, когда приложение представляет каждую vsync.
    • SyncRefreshCount получается в интервале vsync при отправке текущего времени, SyncQPCTime составляет приблизительно время, связанное с интервалом vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Синхронизация кадров для оконных приложений при отключении DWM

При отключении DWM окна приложения отображаются непосредственно на экране монитора без прохождения цепочки перелистывания. В Windows Vista нет поддержки получения сведений о статистике кадров для оконных приложений при отключении DWM. Чтобы поддерживать API, в котором приложениям не требуется учитывать DWM, Windows 7 вернет данные статистики кадров для оконных приложений при отключении DWM. Статистика кадров, возвращаемая только при отключении DWM, оценивается только.

Пошаговое руководство по модели переверки Direct3D 9Ex и представление примера статистики

Чтобы выбрать презентацию FlipEx для Примера Direct3D 9Ex

  1. Убедитесь, что пример приложения работает в windows 7 или более поздней версии операционной системы.
  2. Задайте для элемента SwapEffect D3DPRESENT_PARAMETERS значение D3DSWAPEFFECT_FLIPEX в вызове 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;
    }

Чтобы также принять участие в примере FlipEx associated Present Statistics for 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;
    }

Чтобы избежать, обнаружить и восстановить сбои

  1. Вызовы в очереди: рекомендуемое количество обратных вызовов составляет от 2 до 4.

  2. Пример Direct3D 9Ex добавляет неявный backbuffer, фактическая длина очереди present имеет значение backbuffer count + 1.

  3. Создайте структуру вспомогательной очереди для хранения всех успешно отправленных идентификаторов докладчика (PresentCount) и связанных, вычисляемых или ожидаемых PresentRefreshCount.

  4. Чтобы обнаружить вхождение сбоя, выполните приведенные действия.

    • Вызов GetPresentStatistics.
    • Получение идентификатора (PresentCount) и счетчика vsync, где отображается кадр (PresentRefreshCount) кадра, который получает текущую статистику.
    • Получите ожидаемое значение PresentRefreshCount (TargetRefresh в примере кода), связанное с идентификатором докладчика.
    • Если фактическое значение PresentRefreshCount позже, чем ожидалось, произошел сбой.
  5. Чтобы восстановиться после сбоя, выполните приведенные действия.

    • Вычислите, сколько кадров пропускается (g_ переменная iImmediates в примере кода).
    • Представление пропущенных кадров с интервалом D3DPRESENT_FORCEIMMEDIATE.

Рекомендации по обнаружению и восстановлению сбоя

  1. Восстановление сбоем принимает N (g_iQueueDelay переменную в примере кода) число вызовов Present, где N (g_iQueueDelay) равно g_iImmediates плюс длина очереди Present, то есть:

    • Пропуск кадров с D3DPRESENT_FORCEIMMEDIATE текущего интервала, а также
    • Очередные подарки, которые необходимо обработать
  2. Задайте ограничение на длину сбоя (GLITCH_RECOVERY_LIMIT в примере). Если пример приложения не может восстановиться после слишком длинного сбоя (то есть 1 секунды или 60 vsyncs на мониторе 60Гц), перейдите к промежуточной анимации и сбросите очередь вспомогательного средства докладчика.

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

Пример сценария

  • На следующем рисунке показано приложение с числом backbuffer 4. Следовательно, длина текущей очереди составляет 5.

    иллюстрация отрисованных кадров и соответствующих очередей

    Кадр A предназначен для перехода на экран на количество интервалов синхронизации 1, но было обнаружено, что он был показан на счетчике интервалов синхронизации 4. Поэтому произошел сбой. Последующие 3 кадра представлены с D3DPRESENT_INTERVAL_FORCEIMMEDIATE. Сбой должен принимать в общей сложности 8 вызовов, прежде чем он будет восстановлен, — следующий кадр будет отображаться как по его целевому количеству интервалов синхронизации.

Сводка рекомендаций по программированию для синхронизации кадров

  • Создайте список резервных копий всех идентификаторов LastPresentCount (полученных с помощью GetLastPresentCount) и связанных предполагаемых данных PresentRefreshCount всех отправленных презентаций.

    Примечание.

    Когда приложение вызывает PresentEx с D3DPRESENT_DONOTFLIP, вызов GetPresentStatistics завершается успешно, но не возвращает обновленную структуру D3DPRESENTSTATS, когда приложение находится в окне.

  • Вызовите GetPresentStatistics , чтобы получить фактическую функцию PresentRefreshCount, связанную с каждым отображаемым идентификатором кадров, чтобы убедиться, что приложение обрабатывает сбой из вызова.

  • Если фактическое значение PresentRefreshCount позже, чем предполагаемое Значение PresentRefreshCount, обнаруживается сбой. Компенсируйте, отправляя отстающие кадры с помощью D3DPRESENT_FORCEIMMEDIATE.

  • При представлении одного кадра в конце очереди "Текущее" все последующие кадры очереди будут представлены поздно. D3DPRESENT_FORCEIMMEDIATE исправит только следующий кадр, который будет представлен после всех очередных кадров. Таким образом, очередь "Текущее" или счетчика backbuffer не должно быть слишком длинным - поэтому есть меньше сбоев кадров, чтобы догнать. Оптимальное число обратных заборов — от 2 до 4.

  • Если предполагаемое значение PresentRefreshCount позже фактического PresentRefreshCount, возможно, произошло регулирование DWM. Возможны следующие решения:

    • уменьшение длины очереди
    • сокращение требований к памяти GPU с другими средствами, помимо уменьшения длины очереди (т. е. уменьшения качества, удаления эффектов и т. д.)
    • указание DwmEnableMMCSS для предотвращения регулирования DWM в целом
  • Проверьте функциональность отображения приложения и производительность статистики кадров в следующих сценариях:

    • с dwM включено и выключение
    • полноэкранные монопольные и оконные режимы
    • оборудование с меньшими возможностями
  • Если приложения не могут восстановиться из большого количества сбойных кадров с D3DPRESENT_FORCEIMMEDIATE Present, они могут выполнять следующие операции:

    • Сокращение использования ЦП и GPU путем отрисовки с меньшей рабочей нагрузкой.
    • в случае декодирование видео, декодирования быстрее путем снижения качества и, следовательно, использования ЦП и GPU.

Вывод об улучшениях Direct3D 9Ex

В Windows 7 приложения, отображающие частоту кадров видео или датчика во время презентации, могут выбрать модель flip. Существующие улучшения статистики, связанные с функцией Flip Model Direct3D 9Ex, могут воспользоваться приложениями, которые синхронизируют презентацию на частоту кадров с обратной связью в режиме реального времени для обнаружения и восстановления сбоя. Разработчики, которые принимают модель Direct3D 9Ex Flip, должны учитывать отдельную HWND от содержимого GDI и синхронизацию частоты кадров. Дополнительные сведения см. в этом разделе. Дополнительные сведения см . в центре разработчиков DirectX на сайте MSDN.

Призыв к действию

Мы рекомендуем использовать модель Direct3D 9Ex Flip и ее текущую статистику в Windows 7 при создании приложений, пытающихся синхронизировать частоту кадров презентации или восстанавливаться после сбоев отображения.

Центр разработчиков DirectX в MSDN