В Direct3D 11 отсутствует GetRasterStatus, как определить период вертикальной пустоты? - PullRequest
11 голосов
/ 13 июля 2011

Я обновляю приложение, в котором измерение времени представления стимула на экране требует наибольшей точности.В настоящее время он написан для DirectDraw, который давно выпущен на пастбище, и есть необходимость обновить нашу графическую библиотеку.

Способ, которым мы измеряем время представления, использует обнаружение конца вертикальной пробела.период.В частности, мне нужно знать с максимально возможной точностью, когда все, что было перевернуто на первичную поверхность (или представлено в цепочке обмена), фактически рисуется экраном.Обнаружение линии сканирования может повысить достоверность этого измерения, но я мог бы работать только с обнаружением, когда период вертикального бланка закончился сразу после вызова функции Flip or Present.

Direct 3D 9 имеет IDirect3DDevice9 :: GetRasterStatus Method , который возвращает структуру D3DRASTER_STATUS, которая включает логическое значение InVBlank, которое описывает, находится ли устройство в вертикальной пробел, а также текущую строку сканирования.DirectDraw имеет аналогичные функции ( IDirectDraw :: GetVerticalBlankStatus , также IDirectDraw :: GetScanLine, который возвращает DDERR_VERTICALBLANKINPROGRESS во время вертикальной пробела, может использоваться для обнаружения VB).

Однако я не смог найти аналогичной функции в Direct3D11.Кто-нибудь знает, была ли эта функциональность перемещена или удалена между Direct3D9 и Direct3D11, и если последняя, ​​почему?

Ответы [ 3 ]

3 голосов
/ 26 февраля 2017

Извините за поздний ответ, но я заметил, что до сих пор нет принятого ответа, так что, возможно, вы никогда не нашли тот, который работал. В настоящее время в Windows служба DesktopWindowManager (dwm.exe) координирует все и не может быть обойдена. Начиная с Windows 8, эта служба не может быть отключена.

Таким образом, DWM всегда будет контролировать частоту кадров, управление очередью рендеринга и окончательную композицию для всех различных IDXGISurface ( n ) объектов и IDXGIOutput ( n ) контролирует и не очень много пользуется для отслеживания VSync для цели закадрового рендера, если я что-то упустил (без сарказма). Что касается вашего вопроса, я не был уверен, что ваша цель:

  1. получить чрезвычайно точную информацию о времени, но только для диагностики, профилирования или информационного использования, или
  2. собиралось ли приложение затем (пытаться) использовать эти результаты для (попытки) планировать свои собственные текущие циклы.

Если это последнее, я считаю, что вы можете эффективно сделать это только в том случае, если приложение D3D работает в режиме в полноэкранном режиме . Это единственный случай, когда DWM - под видом DXGI - будет по-настоящему доверять клиенту обработку собственного Present времени.

(едва) хорошая новость заключается в том, что если ваш интерес к VSync носит исключительно информационный характер, то есть вы попадаете в категорию пули (1.) сверху, то вы действительно можете получить все данные синхронизации, которые вам когда-либо понадобятся, и с разрешением QueryPerformanceFrequency , которое обычно составляет около 320 нс.

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

DWM_TIMING_INFO

Указывает информацию о времени компоновки Desktop Window Manager (DWM). Используется функцией DwmGetCompositionTimingInfo .

typedef struct _DWM_TIMING_INFO
{
    UINT32    cbSize;                 // size of this DWM_TIMING_INFO structure
    URATIO    rateRefresh;            // monitor refresh rate
    QPC_TIME  qpcRefreshPeriod;       // monitor refresh period
    URATIO    rateCompose;            // composition rate
    QPC_TIME  qpcVBlank;              // query performance counter value before the vertical blank
    CFRAMES   cRefresh;               // DWM refresh counter
    UINT      cDXRefresh;             // DirectX refresh counter
    QPC_TIME  qpcCompose;             // query performance counter value for a frame composition
    CFRAMES   cFrame;                 // frame number that was composed at qpcCompose
    UINT      cDXPresent;             // DirectX present number used to identify rendering frames
    CFRAMES   cRefreshFrame;          // refresh count of the frame that was composed at qpcCompose
    CFRAMES   cFrameSubmitted;        // DWM frame number that was last submitted
    UINT      cDXPresentSubmitted;    // DirectX present number that was last submitted
    CFRAMES   cFrameConfirmed;        // DWM frame number that was last confirmed as presented
    UINT      cDXPresentConfirmed;    // DirectX present number that was last confirmed as presented
    CFRAMES   cRefreshConfirmed;      // target refresh count of the last frame confirmed as completed by the GPU
    UINT      cDXRefreshConfirmed;    // DirectX refresh count when the frame was confirmed as presented
    CFRAMES   cFramesLate;            // number of frames the DWM presented late
    UINT      cFramesOutstanding;     // number of composition frames that have been issued but have not been confirmed as completed
    CFRAMES   cFrameDisplayed;        // last frame displayed
    QPC_TIME  qpcFrameDisplayed;      // QPC time of the composition pass when the frame was displayed
    CFRAMES   cRefreshFrameDisplayed; // vertical refresh count when the frame should have become visible
    CFRAMES   cFrameComplete;         // ID of the last frame marked as completed
    QPC_TIME  qpcFrameComplete;       // QPC time when the last frame was marked as completed
    CFRAMES   cFramePending;          // ID of the last frame marked as pending
    QPC_TIME  qpcFramePending;        // QPC time when the last frame was marked as pending
    CFRAMES   cFramesDisplayed;       // number of unique frames displayed
    CFRAMES   cFramesComplete;        // number of new completed frames that have been received
    CFRAMES   cFramesPending;         // number of new frames submitted to DirectX but not yet completed
    CFRAMES   cFramesAvailable;       // number of frames available but not displayed, used, or dropped
    CFRAMES   cFramesDropped;         // number of rendered frames that were never displayed because composition occurred too late
    CFRAMES   cFramesMissed;          // number of times an old frame was composed when a new frame should have been used but was not available
    CFRAMES   cRefreshNextDisplayed;  // frame count at which the next frame is scheduled to be displayed
    CFRAMES   cRefreshNextPresented;  // frame count at which the next DirectX present is scheduled to be displayed
    CFRAMES   cRefreshesDisplayed;    // total number of refreshes that have been displayed for the application since the DwmSetPresentParameters function was last called
    CFRAMES   cRefreshesPresented;    // total number of refreshes that have been presented by the application since DwmSetPresentParameters was last called
    CFRAMES   cRefreshStarted;        // refresh number when content for this window started to be displayed
    ULONGLONG cPixelsReceived;        // total number of pixels DirectX redirected to the DWM
    ULONGLONG cPixelsDrawn;           // number of pixels drawn
    CFRAMES   cBuffersEmpty;          // number of empty buffers in the flip chain
}
DWM_TIMING_INFO;

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

typedef UNSIGNED_RATIO URATIO;
typedef DWM_FRAME_COUNT DWMFC;
typedef QPC_TIME QPCT;

Теперь для приложений, работающих в оконном режиме , вы, безусловно, можете получать эту подробную информацию так часто, как захотите. Если вам нужно только пассивное профилирование, то получение данных из DwmGetCompositionTimingInfo - это современный способ сделать это.

Если говорить о современном, так как вопрос намекает на модернизацию, вы можете рассмотреть возможность использования IDXGISwapChain1 , полученного из IDXGIFactory2 :: CreateSwapChainForComposition , чтобы включить использование нового DirectComposition компонент.

DirectComposition обеспечивает богатые и плавные переходы за счет достижения высокой частоты кадров, использования графического оборудования и работы независимо от потока пользовательского интерфейса. DirectComposition может принимать растровое содержимое, отображаемое различными библиотеками рендеринга, включая растровые изображения Microsoft DirectX и растровые изображения, отображаемые в окне (растровые изображения HWND). Кроме того, DirectComposition поддерживает различные преобразования, такие как двухмерные аффинные преобразования и трехмерные перспективные преобразования, а также основные эффекты, такие как отсечение и непрозрачность.

В любом случае, менее вероятно, что подробная информация о времени может с пользой сообщить поведение приложения во время выполнения; возможно это поможет вам предсказать ваш следующий VSync, но один не задается вопросом, какое значение может иметь «острое осознание периода гашения» для некоторого конкретного DWM-подчиненного закадровый обмен цепочки.

BecТак как поверхность вашего приложения - лишь одна из многих, с которыми DWM манипулирует, DWM будет выполнять все виды динамической адаптации самостоятельно, исходя из предположения, что каждый клиент ведет себя последовательно.Непредсказуемые адаптации не способствуют сотрудничеству в таком режиме и, скорее всего, просто приведут в замешательство обе стороны.




Примечания:
1.Разрешение QPC на много порядков выше разрешения тика DateTime, несмотря на предполагаемое использование последним 100 нс.единица наименования.Думайте о DateTime.Now.Ticks как о переупаковке (обозначенной в миллисекундах) Environment.TickCount, но преобразованной в единицы по 100 нс.Для максимально возможного разрешения используйте статический метод Stopwatch.GetTimestamp() вместо DateTime.Now.Ticks.
1 голос
/ 04 апреля 2018

Другая альтернатива:

Существует D3DKMTGetScanLine () , которая работает с D3D9, D3D10, D3D11, D3D12 и даже OpenGL.

На самом деле это функция GDI32, так что вы можете использовать существующий графический интерфейс hAdaptor для опроса VBlank / Scanline - нет необходимости создавать кадровый буфер Direct3D.Вот почему этот API отлично работает с рендерерами OpenGL, Mantle и не Direct3D, несмотря на префикс D3D этого вызова API.

Он также сообщает вам статус VBlank и строку сканирования растра.

Это полезно для гонок на лучах в критически важных приложениях.Некоторые виртуальные реальности используют гонки на лучах, когда даже 20-миллиметровая задержка может означать разницу между приятной виртуальной реальностью и головокружительной / притягательной виртуальной реальностью.

Лучевая гонка - это рендеринг на лету, после сканирования дисплея.В специализированных приложениях, критичных к задержке, вы можете уменьшить задержку от Direct3D Present () до пикселей, поражающих ваши глазные яблоки, до абсолютного минимума (всего 3 мс).

Чтобы понять, что такое лучевая гонка, https://www.wired.com/2009/03/racing-the-beam/ - это было обычным явлением в те времена, когда графические чипы не имели кадровых буферов - создание гонок лучей необходимо для улучшения графики на Atari 2600, Nintendo, Commodore 64 и т. д ...

Для более современной реализациигонки лучей, см. Алгоритм без отставания VSYNC ON для эмуляторов .

0 голосов
/ 22 мая 2012

Вопрос здесь в том, почему? Похоже, вы хотите решить симптом вашей проблемы; может быть, это отвлекает от вашей реальной проблемы. Ожидание vsync было полезной техникой на Amiga или DOS. Это абсолютно неправильно в любой композитной или многопоточной ОС.

Во-первых, чего вы хотите достичь? Рендеринг без разрывов выполняется путем установки интервала подкачки в D3D или OpenGL. Вредно пытаться делать лучше, чем там ОС. Подумайте о случаях, например, о нескольких мониторах, или о том, что произойдет, если более чем одно приложение попытается синхронизировать.

Если вы являетесь клиентом какого-либо другого процесса и хотите запустить синхронизацию на VSync, то, к сожалению, Windows не предлагает никаких объектов для ожидания, насколько я знаю. Лучше всего по-прежнему полагаться на текущий вызов и оценивать происходящее.

Есть два случая: вы рендерите (представляете) быстрее или медленнее, чем vsync. Если вы быстрее, Present должен блокироваться для вас. Если подарок никогда не ждет и ваше время между вызовами превышает 1/60 секунды, вы, вероятно, захотите рендериться реже.

Наиболее распространенным случаем, почему люди заботятся о VSync, является видео. Вы можете рендерить намного быстрее, чем vsync, но хотите дождаться нужного времени для презентации. Единственное, что нужно сделать, это запустить несколько кадров так быстро, как вы можете, и исходя из этой оценки, вы рассчитываете время кадра. Используйте джиттер и обратную связь ... или используйте встроенное аппаратное видео, которое достаточно для того, чтобы дружить с ядром с видеодрайвером.

...