Модель flip, грязное прямоугольники, прокрученные области

DXGI 1.2 поддерживает новую цепочку буферов модели flip, грязное прямоугольники и прокрученные области. Мы объясним преимущества использования новой цепочки буферов модели flip и оптимизации представления, указав грязное прямоугольников и прокручиваемых областей.

Презентация модели флип-модели DXGI

DXGI 1.2 добавляет поддержку модели представления flip для API Direct3D 10 и более поздних версий. В Windows 7 Direct3D 9EX впервые приняла представление модели flip, чтобы избежать без необходимости копирования буфера цепочки буферов. При использовании модели flip задние буферы переключаются между средой выполнения и диспетчером окон рабочего стола (DWM), поэтому DWM всегда состоит непосредственно из заднего буфера, а не копирует содержимое обратного буфера.

API DXGI 1.2 включают в себя измененный интерфейс цепочки буферов DXGI IDXGISwapChain1. Вы можете использовать несколько методов интерфейса IDXGIFactory2 , чтобы создать соответствующий объект IDXGISwapChain1 для использования с дескриптором HWND , объектом CoreWindow , DirectComposition или платформой Windows.UI.Xaml .

Чтобы выбрать модель представления flip, укажите значение перечисления DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL в элементе SwapEffect структуры DXGI_SWAP_CHAIN_DESC1 и задайте для элемента BufferCountDXGI_SWAP_CHAIN_DESC1 значение не менее 2. Дополнительные сведения об использовании модели сальто DXGI см. в разделе Модель сальто DXGI. Из-за более плавной презентации и других новых функциональных возможностей, мы рекомендуем использовать модель представления flip для всех новых приложений, которые вы пишете с помощью API Direct3D 10 и более поздних версий.

Использование грязное прямоугольников и прямоугольника прокрутки в презентации цепочки буферов

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

Прокрутку можно использовать только с цепочками буферов DXGI, которые выполняются в модели представления с пролистыванием. Вы можете использовать грязное прямоугольники с цепочками буферов DXGI, которые выполняются как в модели flip, так и в модели bitblt (с DXGI_SWAP_EFFECT_SEQUENTIAL).

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

Приложение выполняет презентацию путем вызова метода IDXGISwapChain1::P resent1 . В этом вызове приложение передает указатель на структуру DXGI_PRESENT_PARAMETERS, которая включает в себя грязное прямоугольников и количество грязное прямоугольников, прямоугольник прокрутки и связанное смещение прокрутки или оба грязное прямоугольники и прямоугольник прокрутки. Наше приложение передает 2 грязное прямоугольников и прямоугольников прокрутки. Прямоугольник прокрутки — это область предыдущего кадра, которую операционная система должна скопировать в текущий кадр перед отрисовки текущего кадра. Приложение задает анимацию видео и новую строку как грязное прямоугольники, а операционная система отрисовывает их в текущем кадре.

Иллюстрация перекрытия прямоугольников прокрутки и грязное

DirtyRectsCount = 2
pDirtyRects[ 0 ] = { 10, 30, 40, 50 } // Video
pDirtyRects[ 1 ] = { 0, 70, 50, 80 } // New line
*pScrollRect = { 0, 0, 50, 70 }
*pScrollOffset = { 0, -10 }

Пунктирный прямоугольник отображает прямоугольник прокрутки в текущем кадре. Прямоугольник прокрутки задается элементом pScrollRectDXGI_PRESENT_PARAMETERS. Стрелка показывает смещение прокрутки. Смещение прокрутки задается элементом pScrollOffsetDXGI_PRESENT_PARAMETERS. Заполненные прямоугольники отображают грязное прямоугольники, которые приложение обновило новым содержимым. Заполненные прямоугольники задаются элементами DirtyRectsCount и pDirtyRectsDXGI_PRESENT_PARAMETERS.

Пример 2-буферной цепочки буферов с моделью переворачивания с грязное прямоугольниками и прямоугольником прокрутки

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

  1. Как показано в переднем буфере в начале кадра, прокручиваемое приложение изначально отображает кадр с текстом и анимацией видео.
  2. Для отрисовки следующего кадра приложение отображает на заднем буфере прямоугольники грязное, которые обновляют анимационный видеоролик и новую строку окна.
  3. Когда приложение вызывает IDXGISwapChain1::P resent1, оно указывает грязное прямоугольники, а также прямоугольник прокрутки и смещение. Далее среда выполнения копирует прямоугольник прокрутки из предыдущего кадра за вычетом обновленных прямоугольников грязное в текущий задний буфер.
  4. Наконец, среда выполнения переключает передний и задний буферы.

Пример цепочки буферов модели flip с прямоугольниками прокрутки и грязное

Отслеживание грязное прямоугольников и прямоугольников прокрутки в нескольких кадрах

При использовании грязное прямоугольников в приложении необходимо отслеживать грязное прямоугольники для поддержки добавочной отрисовки. Когда приложение вызывает IDXGISwapChain1::P resent1 с грязное прямоугольниками, необходимо убедиться, что каждый пиксель в грязное прямоугольников обновлен. Если вы не полностью перерисовывайте всю область грязное прямоугольника или если вы не можете знать наверняка области, которые загрязняются, необходимо скопировать некоторые данные из предыдущего полностью согласованного обратного буфера в текущий устаревший обратный буфер, прежде чем начать отрисовку.

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

  1. Представление грязное прямоугольника в кадре 1.
  2. Скопируйте пересечение между прямоугольником грязное из кадра 1 и прямоугольником грязное из кадра 2 в грязное прямоугольник фрейма 2.
  3. Представление грязное прямоугольника в кадре 2.

отслеживание прокрутки и грязное прямоугольников в нескольких кадрах

Чтобы обобщить, для цепочки буферов с N буферов, область, которую среда выполнения копирует из последнего кадра в текущий кадр текущего кадра, будет следующим:

уравнение для вычисления области, копируемый средой выполнения

где buffer указывает индекс буфера в цепочке буферов, начиная с текущего индекса буфера с нулевым значением.

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

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

Отслеживание одного пересечения между двумя грязное прямоугольниками

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

В этом фрагменте кода вызов IntersectRect возвращает пересечение двух грязное прямоугольников в другом RECT под названием dirtyRectCopy. После того как фрагмент кода определяет, что два прямоугольника грязное пересекаются, он вызывает метод ID3D11DeviceContext1::CopySubresourceRegion1 для копирования области пересечения в текущий кадр.

RECT dirtyRectPrev, dirtyRectCurrent, dirtyRectCopy;
 
if (IntersectRect( &dirtyRectCopy, &dirtyRectPrev, &dirtyRectCurrent ))
{
       D3D11_BOX intersectBox;
       intersectBox.left    = dirtyRectCopy.left;
       intersectBox.top     = dirtyRectCopy.top;
       intersectBox.front   = 0;
       intersectBox.right   = dirtyRectCopy.right;
       intersectBox.bottom  = dirtyRectCopy.bottom;
       intersectBox.back    = 1;
 
       d3dContext->CopySubresourceRegion1(pBackbuffer,
                                    0,
                                    0,
                                    0,
                                    0,
                                    pPrevBackbuffer,
                                    0,
                                    &intersectBox,
                                    0
                                    );
}

// Render additional content to the current pBackbuffer and call Present1.

Если вы используете этот фрагмент кода в приложении, приложение будет готово вызвать IDXGISwapChain1::P resent1, чтобы обновить текущий кадр с помощью текущего прямоугольника грязное.

Отслеживание пересечений между N грязное прямоугольниками

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

В этом фрагменте кода мы вызываем функцию GDI SetRectRgn для преобразования каждого грязное прямоугольника в прямоугольную область, а затем вызываем функцию GDI CombineRgn, чтобы объединить все грязное прямоугольные области в группу.

HRGN hDirtyRgnPrev, hDirtyRgnCurrent, hRectRgn; // Handles to regions 
// Save all the dirty rectangles from the previous frame.
 
RECT dirtyRect[N]; // N is the number of dirty rectangles in current frame, which includes newly scrolled area.
 
int iReturn;
SetRectRgn(hDirtyRgnCurrent, 
       dirtyRect[0].left, 
       dirtyRect[0].top, 
       dirtyRect[0].right, 
       dirtyRect[0].bottom 
       );

for (int i = 1; i<N; i++)
{
   SetRectRgn(hRectRgn, 
          dirtyRect[0].left, 
          dirtyRect[0].top, 
          dirtyRect[0].right, 
          dirtyRect[0].bottom 
          );

   iReturn = CombineRgn(hDirtyRgnCurrent,
                        hDirtyRgnCurrent,
                        hRectRgn,
                        RGN_OR
                        );
   // Handle the error that CombineRgn returns for iReturn.
}

Теперь вы можете использовать функцию GDI CombineRgn, чтобы определить пересечение между грязное областью предыдущего кадра и грязное областью текущего кадра. Получив пересекающуюся область, вызовите функцию GDI GetRegionData , чтобы получить каждый отдельный прямоугольник из пересекающейся области, а затем вызовите метод ID3D11DeviceContext1::CopySubresourceRegion1 , чтобы скопировать каждый пересекающийся прямоугольник в текущий задний буфер. В следующем фрагменте кода показано, как использовать эти функции GDI и Direct3D.

HRGN hIntersectRgn;
bool bRegionsIntersect;
iReturn = CombineRgn(hIntersectRgn, hDirtyRgnCurrent, hDirtyRgnPrev, RGN_AND);
if (iReturn == ERROR)
{
       // Handle error.
}
else if(iReturn == NULLREGION)
{
       bRegionsIntersect = false;
}
else
{
       bRegionsIntersect = true;
}
 
if (bRegionsIntersect)
{
       int rgnDataSize = GetRegionData(hIntersectRgn, 0, NULL);
       if (rgnDataSize)
       {
              char pMem[] = new char[size];
              RGNDATA* pRgnData = reinterpret_cast<RGNDATA*>(pMem);
              iReturn = GetRegionData(hIntersectRgn, rgnDataSize, pRgnData);
              // Handle iReturn failure.
 
              for (int rectcount = 0; rectcount < pRgnData->rdh.nCount; ++r)
              {
                     const RECT* pIntersectRect = reinterpret_cast<RECT*>(pRgnData->Buffer) +                                            
                                                  rectcount;                
                     D3D11_BOX intersectBox;
                     intersectBox.left    = pIntersectRect->left;
                     intersectBox.top     = pIntersectRect->top;
                     intersectBox.front   = 0;
                     intersectBox.right   = pIntersectRect->right;
                     intersectBox.bottom  = pIntersectRect->bottom;
                     intersectBox.back    = 1;
 
                     d3dContext->CopySubresourceRegion1(pBackbuffer,
                                                      0,
                                                      0,
                                                      0,
                                                      0,
                                                      pPrevBackbuffer,
                                                      0,
                                                      &intersectBox,
                                                      0
                                                      );
              }

              delete [] pMem;
       }
}

Цепочка буферов модели Bitblt с грязное прямоугольниками

Вы можете использовать грязное прямоугольники с цепочками буферов DXGI, которые выполняются в bitblt-модели (с DXGI_SWAP_EFFECT_SEQUENTIAL). Цепочки буферов модели Bitblt, использующие более одного буфера, также должны отслеживать перекрывающиеся грязное прямоугольники между кадрами так же, как описано в разделе Отслеживание грязное прямоугольников и прямоугольников прокрутки между несколькими кадрами для цепочек буферов модели переворачивания. Цепочки буферов модели Bitblt с одним буфером не нужно отслеживать перекрывающиеся грязное прямоугольники, так как весь буфер перерисовывается каждый кадр.

Улучшения DXGI 1.2