Membalik model, persegi panjang kotor, area tergulir

DXGI 1.2 mendukung rantai pertukaran model balik baru, persegi panjang kotor, dan area bergulir. Kami menjelaskan manfaat menggunakan rantai pertukaran model balik baru dan mengoptimalkan presentasi dengan menentukan persegi panjang kotor dan area yang digulir.

Presentasi model balik DXGI

DXGI 1.2 menambahkan dukungan untuk model presentasi balik untuk Direct3D 10 dan API yang lebih baru. Di Windows 7, Direct3D 9EX pertama kali mengadopsi presentasi model balik untuk menghindari penyalinan buffer rantai pertukaran yang tidak perlu. Dengan menggunakan model flip, buffer belakang dibalik antara runtime dan Desktop Window Manager (DWM), sehingga DWM selalu menyusun langsung dari buffer belakang alih-alih menyalin konten buffer belakang.

API DXGI 1.2 mencakup antarmuka rantai swap DXGI yang direvisi, IDXGISwapChain1. Anda dapat menggunakan beberapa metode antarmuka IDXGIFactory2 untuk membuat objek IDXGISwapChain1 yang sesuai untuk digunakan dengan handel HWND , objek CoreWindow , DirectComposition, atau kerangka kerja Windows.UI.Xaml .

Anda memilih model presentasi balik dengan menentukan nilai enumerasi DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL di anggota SwapEffect dari struktur DXGI_SWAP_CHAIN_DESC1 dan dengan mengatur anggota BufferCountdari DXGI_SWAP_CHAIN_DESC1 ke minimal 2. Untuk informasi selengkapnya tentang cara menggunakan model flip DXGI, lihat model flip DXGI. Karena presentasi model presentasi yang lebih halus dan fungsionalitas baru lainnya, kami sarankan Anda menggunakan model presentasi balik untuk semua aplikasi baru yang Anda tulis dengan Direct3D 10 dan API yang lebih baru.

Menggunakan persegi kotor dan persegi panjang gulir dalam presentasi rantai pertukaran

Dengan menggunakan persegi kotor dan persegi panjang gulir dalam presentasi rantai pertukaran, Anda menghemat penggunaan bandwidth memori dan penggunaan daya sistem terkait karena jumlah data piksel yang dibutuhkan sistem operasi untuk menggambar bingkai berikutnya yang disajikan dikurangi jika sistem operasi tidak perlu menggambar seluruh bingkai. Untuk aplikasi yang sering ditampilkan melalui Koneksi Desktop Jarak Jauh dan teknologi akses jarak jauh lainnya, penghematannya sangat terlihat dalam kualitas tampilan karena teknologi ini menggunakan persegi panjang kotor dan metadata gulir.

Anda hanya dapat menggunakan gulir dengan rantai pertukaran DXGI yang berjalan dalam model presentasi balik. Anda dapat menggunakan persegi panjang kotor dengan rantai pertukaran DXGI yang berjalan dalam model flip dan model bitblt (diatur dengan DXGI_SWAP_EFFECT_SEQUENTIAL).

Dalam skenario dan ilustrasi ini kami menunjukkan fungsionalitas menggunakan persegi panjang kotor dan menggulir. Di sini, aplikasi yang dapat digulir berisi teks dan video animasi. Aplikasi ini menggunakan persegi panjang kotor untuk hanya memperbarui video animasi dan baris baru untuk jendela, alih-alih memperbarui seluruh jendela. Persegi panjang gulir memungkinkan sistem operasi untuk menyalin dan menerjemahkan konten yang dirender sebelumnya pada bingkai baru dan hanya merender baris baru pada bingkai baru.

Aplikasi ini melakukan presentasi dengan memanggil metode IDXGISwapChain1::P resent1 . Dalam panggilan ini, aplikasi meneruskan pointer ke struktur DXGI_PRESENT_PARAMETERS yang mencakup persegi panjang kotor dan jumlah persegi panjang kotor, atau persegi panjang gulir dan offset gulir terkait, atau persegi panjang kotor dan persegi panjang gulir. Aplikasi kami melewati 2 persegi panjang kotor dan persegi panjang gulir. Persegi panjang gulir adalah area bingkai sebelumnya yang perlu disalin oleh sistem operasi ke bingkai saat ini sebelum merender bingkai saat ini. Aplikasi ini menentukan video animasi dan baris baru sebagai persegi panjang kotor, dan sistem operasi merendernya pada bingkai saat ini.

ilustrasi gulir dan persegi panjang kotor yang tumpang tindih

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 }

Persegi panjang putus-putus memperlihatkan persegi panjang gulir dalam bingkai saat ini. Persegi panjang gulir ditentukan oleh anggota pScrollRectdari DXGI_PRESENT_PARAMETERS. Panah menunjukkan offset gulir. Offset gulir ditentukan oleh anggota pScrollOffsetdari DXGI_PRESENT_PARAMETERS. Persegi panjang yang diisi menunjukkan persegi panjang kotor yang diperbarui aplikasi dengan konten baru. Persegi panjang yang diisi ditentukan oleh anggota DirtyRectsCount dan pDirtyRectsdari DXGI_PRESENT_PARAMETERS.

Sampel rantai pertukaran 2-buffer flip-model dengan persegi panjang kotor dan persegi panjang gulir

Ilustrasi dan urutan berikutnya menunjukkan contoh operasi presentasi model balik DXGI yang menggunakan persegi panjang kotor dan persegi panjang gulir. Dalam contoh ini kita menggunakan jumlah minimum buffer untuk presentasi model balik, yang merupakan jumlah buffer dua, satu buffer depan yang berisi konten tampilan aplikasi dan satu buffer kembali yang berisi bingkai saat ini yang ingin dirender aplikasi.

  1. Seperti yang ditunjukkan di buffer depan di awal bingkai, aplikasi yang dapat digulir awalnya menampilkan bingkai dengan beberapa teks dan video animasi.
  2. Untuk merender bingkai berikutnya, aplikasi dirender ke buffer belakang persegi panjang kotor yang memperbarui video animasi dan baris baru untuk jendela.
  3. Saat aplikasi memanggil IDXGISwapChain1::P resent1, aplikasi menentukan persegi kotor dan persegi panjang dan offset gulir. Runtime berikutnya menyalin persegi panjang gulir dari bingkai sebelumnya dikurangi persegi panjang kotor yang diperbarui ke buffer belakang saat ini.
  4. Runtime akhirnya menukar buffer depan dan belakang.

contoh rantai pertukaran model balik dengan gulir dan persegi panjang kotor

Melacak persegi kotor dan menggulir persegi panjang di beberapa bingkai

Saat Anda menggunakan persegi panjang kotor di aplikasi, Anda harus melacak persegi panjang kotor untuk mendukung penyajian bertahap. Saat aplikasi Anda memanggil IDXGISwapChain1::P resent1 dengan persegi panjang kotor, Anda harus memastikan bahwa setiap piksel dalam persegi panjang kotor sudah diperbarui. Jika Anda tidak sepenuhnya merender kembali seluruh area persegi panjang kotor atau jika Anda tidak tahu dengan pasti area yang kotor, Anda harus menyalin beberapa data dari buffer belakang yang sepenuhnya koheren sebelumnya ke buffer belakang yang saat ini dan basi sebelum Anda mulai merender.

Runtime hanya menyalin perbedaan antara area yang diperbarui dari bingkai sebelumnya dan area bingkai yang diperbarui ke buffer belakang saat ini. Jika area ini bersinggungan, runtime hanya menyalin perbedaan di antara mereka. Seperti yang Anda lihat dalam diagram dan urutan berikut, Anda harus menyalin persimpangan antara persegi panjang kotor dari bingkai 1 dan persegi panjang kotor dari bingkai 2 ke persegi panjang kotor bingkai 2.

  1. Hadirkan persegi panjang kotor dalam bingkai 1.
  2. Salin persimpangan antara persegi panjang kotor dari bingkai 1 dan persegi panjang kotor dari bingkai 2 ke persegi panjang kotor bingkai 2.
  3. Hadirkan persegi panjang kotor dalam bingkai 2.

melacak gulir dan persegi panjang kotor di beberapa bingkai

Untuk menggeneralisasi, untuk rantai pertukaran dengan buffer N, area yang disalin runtime dari bingkai terakhir ke bingkai saat ini pada bingkai saat ini adalah:

persamaan untuk menghitung area yang disalin runtime

di mana buffer menunjukkan indeks buffer dalam rantai pertukaran, dimulai dengan indeks buffer saat ini pada nol.

Anda dapat melacak persimpangan antara bingkai sebelumnya dan persegi panjang kotor bingkai saat ini dengan menyimpan salinan persegi panjang kotor bingkai sebelumnya atau dengan merender kembali persegi panjang kotor bingkai baru dengan konten yang sesuai dari bingkai sebelumnya.

Demikian pula, dalam kasus di mana rantai pertukaran memiliki lebih dari 2 buffer belakang, Anda harus memastikan bahwa area yang tumpang tindih antara persegi panjang kotor buffer saat ini dan persegi panjang kotor dari semua bingkai sebelumnya disalin atau dirender ulang.

Melacak persimpangan tunggal antara 2 persegi kotor

Dalam kasus yang paling sederhana, ketika Anda memperbarui satu persegi panjang kotor per bingkai, persegi panjang kotor di dua bingkai mungkin bersinggungan. Untuk mengetahui apakah persegi panjang kotor dari bingkai sebelumnya dan persegi panjang kotor bingkai saat ini tumpang tindih, Anda perlu memverifikasi apakah persegi panjang kotor dari bingkai sebelumnya berpotongan dengan persegi panjang kotor dari bingkai saat ini. Anda dapat memanggil fungsi GDI IntersectRect untuk menentukan apakah dua struktur RECT yang mewakili dua persegi panjang kotor berpotongan.

Dalam cuplikan kode ini, panggilan ke IntersectRect mengembalikan persimpangan dua persegi panjang kotor di RECT lain yang disebut dirtyRectCopy. Setelah cuplikan kode menentukan bahwa dua persegi panjang kotor berpotongan, ia memanggil metode ID3D11DeviceContext1::CopySubresourceRegion1 untuk menyalin wilayah persimpangan ke dalam bingkai saat ini.

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.

Jika Anda menggunakan cuplikan kode ini di aplikasi Anda, aplikasi kemudian akan siap untuk memanggil IDXGISwapChain1::P resent1 untuk memperbarui bingkai saat ini dengan persegi panjang kotor saat ini.

Melacak persimpangan antara persegi panjang N kotor

Jika Anda menentukan beberapa persegi panjang kotor, yang dapat menyertakan persegi panjang kotor untuk garis gulir yang baru diungkapkan, per bingkai, Anda perlu memverifikasi dan melacak tumpang tindih yang mungkin terjadi antara semua persegi panjang kotor dari bingkai sebelumnya dan semua persegi panjang kotor dari bingkai saat ini. Untuk menghitung persimpangan antara persegi panjang kotor dari bingkai sebelumnya dan persegi panjang kotor bingkai saat ini, Anda dapat mengelompokkan persegi panjang kotor ke dalam wilayah.

Dalam cuplikan kode ini, kami memanggil fungsi GDI SetRectRgn untuk mengonversi setiap persegi panjang kotor menjadi wilayah persegi panjang dan kemudian kami memanggil fungsi GDI CombineRgn untuk menggabungkan semua wilayah persegi panjang kotor menjadi grup.

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

Anda sekarang dapat menggunakan fungsi GDI CombineRgn untuk menentukan persimpangan antara wilayah kotor bingkai sebelumnya dan wilayah kotor bingkai saat ini. Setelah Anda mendapatkan wilayah yang berpotongan, panggil fungsi GDI GetRegionData untuk mendapatkan setiap persegi panjang individu dari wilayah yang berpotongan lalu panggil metode ID3D11DeviceContext1::CopySubresourceRegion1 untuk menyalin setiap persegi panjang berpotongan ke buffer belakang saat ini. Cuplikan kode berikutnya menunjukkan cara menggunakan fungsi GDI dan Direct3D ini.

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

Rantai pertukaran model Bitblt dengan persegi panjang kotor

Anda dapat menggunakan persegi panjang kotor dengan rantai pertukaran DXGI yang berjalan dalam model bitblt (diatur dengan DXGI_SWAP_EFFECT_SEQUENTIAL). Rantai pertukaran model Bitblt yang menggunakan lebih dari satu buffer juga harus melacak persegi panjang kotor yang tumpang tindih di seluruh bingkai dengan cara yang sama seperti yang dijelaskan dalam Melacak persegi panjang kotor dan menggulir persegi panjang di beberapa bingkai untuk membalik rantai pertukaran model. Rantai pertukaran model Bitblt hanya dengan satu buffer tidak perlu melacak persegi panjang kotor yang tumpang tindih karena seluruh buffer digambar ulang setiap bingkai.

Penyempurnaan DXGI 1.2