Как использовать флип-модель DXGI в оконном приложении Direct2D? - PullRequest
2 голосов
/ 12 марта 2020

У меня есть неигровое оконное приложение Win32, которое использует контекст устройства Direct2D / цель рендеринга HWND для рисования окна. В настоящее время используется цепочка обмена DXGI с эффектом обмена DXGI_SWAP_EFFECT_DISCARD.

Корпорация Майкрософт рекомендует с использованием новых эффектов обмена модели сальто, либо DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, либо DXGI_SWAP_EFFECT_FLIP_DISCARD. Я заинтересован в том, чтобы использовать их в первую очередь потому, что они позволили бы мне указать список грязных каналов при вызове Present1(), что должно улучшить производительность / энергопотребление.

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

Так что вопрос: можно ли использовать в этой ситуации новая своп-модель меняет эффекты, и если да, то как все это настроить ?

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

Цепочка обмена в настоящее время настроена следующим образом:

swapChainDesc.Width = ...;
swapChainDesc.Height = ...;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = 0;

EDIT 1

Оказывается из-за того, что DXGI_SWAP_EFFECT_DISCARD заставляет BufferCount к 1, поэтому мое начальное значение 2 было несколько обманчивым, поскольку используется только один буфер. Источник (3-й комментарий).

Также документы для DXGI_SWAP_EFFECT говорят о том, что приложения UWP принудительно переключаются на модель с переворотом, поэтому это должно быть решаемой проблемой.

1 Ответ

1 голос
/ 17 марта 2020

Есть два хороших способа сделать это.

Первый способ немного сложнее в использовании энергии. Вы можете нарисовать содержимое в промежуточный буфер / текстуру рендеринга и скопировать его в swapchain перед каждым подарком. Таким образом, вы можете визуализировать только те части, которые изменились в вашем промежуточном буфере, и не заботиться о состоянии свопчейна.

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

Кадр 1 - вы рисуете зеленый прямоугольник в (200 x 200) с размерами (150 x 150). Грязная область - это весь кадр, потому что это первый кадр.

Кадр 2 - вы рисуете синий прямоугольник в точке (250 x 250) с размерами (50 x 50). Грязная область (250, 250, 300, 300).

Кадр 3 - вы рисуете красный прямоугольник в (225 x 225) с размерами (50 x 50). Грязная область равна (225, 225, 50, 50).

Если количество буферов равно 2, это означает, что при рисовании кадра 3 необходимо не только перерисовать грязную область (225, 225, 50, 50), но также и грязная область (250, 250, 300, 300).

...