Bagikan melalui


DirectX Graphics Infrastructure (DXGI): Praktik Terbaik

Microsoft DirectX Graphics Infrastructure (DXGI) adalah subsistem baru yang diperkenalkan dengan Windows Vista yang merangkum beberapa tugas tingkat rendah yang diperlukan oleh Direct3D 10, 10.1, 11, dan 11.1. Dari perspektif programmer Direct3D 9, DXGI mencakup sebagian besar kode untuk enumerasi, pembuatan rantai pertukaran, dan presentasi yang sebelumnya dikemas ke dalam API Direct3D 9. Saat Anda memindahkan aplikasi ke DXGI dan Direct3D 10.x dan Direct3D 11.x, Anda perlu mempertimbangkan beberapa pertimbangan untuk memastikan bahwa proses berjalan dengan lancar.

Artikel ini membahas masalah port kunci.

Masalah Full-Screen

Dalam porting dari Direct3D 9 ke DXGI dan ke Direct3D 10.x atau Direct3D 11.x, masalah yang terkait dengan perpindahan dari windowing ke mode layar penuh sering dapat menyebabkan sakit kepala bagi pengembang. Masalah utama muncul karena aplikasi Direct3D 9, tidak seperti aplikasi DXGI, memerlukan pendekatan yang lebih langsung untuk melacak gaya jendela dan status jendela. Ketika kode yang mengubah mode di-port untuk berjalan di DXGI, kode sering menyebabkan perilaku yang tidak terduga.

Seringkali, aplikasi Direct3D 9 menangani transisi ke mode layar penuh dengan mengatur resolusi buffer depan, memaksa perangkat ke mode eksklusif layar penuh, lalu mengatur resolusi buffer belakang agar sesuai. Jalur terpisah digunakan untuk perubahan ukuran jendela karena harus dikelola dari proses jendela setiap kali aplikasi menerima pesan WM_SIZE.

DXGI mencoba menyederhanakan pendekatan ini dengan menggabungkan dua kasus tersebut. Misalnya, saat batas jendela diseret dalam mode berjendela, aplikasi menerima pesan WM_SIZE. DXGI mencegat pesan ini dan secara otomatis mengubah ukuran buffer depan. Yang perlu dilakukan aplikasi adalah memanggil IDXGISwapChain::ResizeBuffers untuk mengubah ukuran buffer belakang ke ukuran yang diteruskan sebagai parameter di WM_SIZE. Demikian pula, ketika aplikasi perlu beralih antara mode layar penuh dan berjendela, aplikasi cukup memanggil IDXGISwapChain::SetFullscreenState. DXGI mengubah ukuran buffer depan agar sesuai dengan mode layar penuh yang baru dipilih, dan mengirimkan pesan WM_SIZE ke aplikasi. Aplikasi kembali memanggil ResizeBuffers, sama seperti jika batas jendela diseret.

Metodologi penjelasan sebelumnya mengikuti jalur yang sangat khusus. DXGI mengatur resolusi layar penuh ke resolusi desktop secara default. Namun, banyak aplikasi beralih ke resolusi layar penuh pilihan. Dalam kasus seperti itu, DXGI menyediakan IDXGISwapChain::ResizeTarget. Ini harus dipanggil sebelum memanggil SetFullscreenState. Meskipun metode ini dapat dipanggil dalam urutan yang berlawanan (SetFullscreenState terlebih dahulu, diikuti oleh ResizeTarget), melakukannya menyebabkan pesan WM_SIZE tambahan dikirim ke aplikasi. (Melakukannya juga dapat menyebabkan kedipan, karena DXGI dapat dipaksa untuk melakukan dua perubahan mode.) Setelah memanggil SetFullscreenState, disarankan untuk memanggil ResizeTarget lagi dengan anggota RefreshRateDXGI_MODE_DESC dikosongkan. Ini berjumlah instruksi tanpa operasi di DXGI, tetapi dapat menghindari masalah dengan laju refresh, yang dibahas berikutnya.

Saat dalam mode layar penuh, Desktop Window Manager (DWM) dinonaktifkan. DXGI dapat melakukan flip untuk menyajikan konten buffer belakang alih-alih melakukan blit, yang akan dilakukannya dalam mode berjendela. Perolehan performa ini dapat dibatalkan, namun, jika persyaratan tertentu tidak terpenuhi. Untuk memastikan bahwa DXGI melakukan flip alih-alih blit, buffer depan dan buffer belakang harus berukuran identik. Jika aplikasi menangani pesan WM_SIZE dengan benar, ini seharusnya tidak menjadi masalah. Selain itu, formatnya harus identik.

Masalah untuk sebagian besar aplikasi adalah laju refresh. Laju refresh yang ditentukan dalam panggilan ke ResizeTarget harus berupa laju refresh yang dijumlahkan oleh objek IDXGIOutput yang digunakan rantai pertukaran. DXGI dapat secara otomatis menghitung nilai ini jika aplikasi nol dari anggota RefreshRatedari DXGI_MODE_DESC yang diteruskan ke ResizeTarget. Penting untuk tidak berasumsi bahwa laju refresh tertentu akan selalu didukung dan hanya mengkodekan nilai secara permanen. Seringkali, pengembang memilih 60 Hz sebagai laju refresh, tidak tahu bahwa laju refresh yang dijumlahkan dari monitor adalah sekitar 60.000 / 1.001 Hz dari monitor. Jika laju refresh tidak cocok dengan kecepatan refresh yang diharapkan 60, DXGI dipaksa untuk melakukan blit dalam mode layar penuh alih-alih membalik.

Masalah terakhir yang sering dihadapi pengembang adalah cara mengubah resolusi layar penuh sambil tetap dalam mode layar penuh. Memanggil ResizeTarget dan SetFullscreenState terkadang berhasil, tetapi resolusi layar penuh tetap menjadi resolusi desktop. Selain itu, pengembang dapat membuat rantai pertukaran layar penuh dan memberikan resolusi tertentu, hanya untuk menemukan bahwa DXGI default ke resolusi desktop terlepas dari angka yang diteruskan. Kecuali diinstruksikan lain, DXGI default ke resolusi desktop untuk rantai pertukaran layar penuh. Saat membuat rantai pertukaran layar penuh, anggota Bendera struktur DXGI_SWAP_CHAIN_DESC harus diatur ke DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH untuk mengambil alih perilaku default DXGI. Bendera ini juga dapat diteruskan ke ResizeTarget untuk mengaktifkan atau menonaktifkan fungsionalitas ini secara dinamis.

Beberapa Monitor

Saat menggunakan DXGI dengan beberapa monitor, ada dua aturan yang harus diikuti.

Aturan pertama berlaku untuk pembuatan dua atau beberapa rantai pertukaran layar penuh pada beberapa monitor. Saat membuat rantai pertukaran seperti itu, yang terbaik adalah membuat semua rantai pertukaran sebagai berjendela, lalu mengaturnya ke layar penuh. Jika rantai pertukaran dibuat dalam mode layar penuh, pembuatan rantai pertukaran kedua menyebabkan perubahan mode dikirim ke rantai pertukaran pertama, yang dapat menyebabkan penghentian mode layar penuh.

Aturan kedua berlaku untuk output. Waspadai output yang digunakan saat membuat rantai pertukaran. Dengan DXGI, kontrol objek IDXGIOutput yang memantau rantai pertukaran menggunakan saat menjadi layar penuh. Tidak seperti DXGI, Direct3D 9 tidak memiliki konsep output.

Gaya Jendela dan DXGI

Aplikasi Direct3D 9 memiliki banyak pekerjaan yang harus dilakukan saat beralih antara mode layar penuh dan berjendela. Sebagian besar pekerjaan ini melibatkan perubahan gaya jendela untuk menambahkan dan menghapus batas, untuk menambahkan bilah gulir, dan sebagainya. Ketika aplikasi di-port ke DXGI dan Direct3D 10.x atau Direct3D 11.x, kode ini sering dibiarkan di tempat. Bergantung pada perubahan yang dilakukan, beralih antar mode dapat menyebabkan perilaku yang tidak terduga. Misalnya, saat beralih ke mode berjendela, aplikasi mungkin tidak lagi memiliki bingkai jendela atau batas jendela meskipun memiliki kode yang secara khusus mengatur gaya ini. Ini terjadi karena DXGI sekarang menangani banyak perubahan gaya ini sendiri. Pengaturan manual gaya jendela dapat mengganggu DXGI, dan ini dapat menyebabkan perilaku yang tidak terduga.

Perilaku yang direkomendasikan adalah melakukan pekerjaan sesedikempat mungkin, dan membiarkan DXGI menangani sebagian besar interaksi dengan jendela. Namun, jika aplikasi perlu menangani perilaku windowing-nya sendiri, IDXGIFactory::MakeWindowAssociation dapat digunakan untuk memberi tahu DXGI untuk menonaktifkan beberapa penanganan jendela otomatisnya.

Multithreading dan DXGI

Perawatan khusus harus dilakukan saat menggunakan DXGI dalam aplikasi multithreaded untuk memastikan bahwa kebuntuan tidak terjadi. Karena interaksi dekat DXGI dengan windowing, kadang-kadang mengirim pesan jendela ke jendela aplikasi terkait. DXGI memerlukan perubahan windowing agar dapat dilanjutkan, sehingga akan menggunakan SendMessage, yang merupakan panggilan sinkron. Aplikasi harus memproses pesan jendela sebelum SendMessage kembali.

Dalam aplikasi di mana DXGI memanggil dan pompa pesan berada di utas yang sama (atau aplikasi utas tunggal), sedikit yang perlu dilakukan. Ketika panggilan DXGI berada di utas yang sama dengan pompa pesan, SendMessage memanggil WindowProc jendela. Ini melewati pompa pesan, dan memungkinkan eksekusi untuk melanjutkan setelah panggilan ke SendMessage. Ingat bahwa panggilan IDXGISwapChain , seperti IDXGISwapChain::P resent, juga dianggap sebagai panggilan DXGI; DXGI dapat menukar pekerjaan dari ResizeBuffers atau ResizeTarget hingga Ada dipanggil.

Jika panggilan DXGI dan pompa pesan berada di utas yang berbeda, perawatan harus dilakukan untuk menghindari kebuntuan. Ketika pompa pesan dan SendMessage berada di utas yang berbeda, SendMessage menambahkan pesan ke antrean pesan jendela, dan menunggu jendela memproses pesan tersebut. Jika prosedur jendela sibuk atau tidak dipanggil oleh pompa pesan, pesan mungkin tidak pernah diproses dan DXGI akan menunggu tanpa batas waktu.

Misalnya, jika aplikasi yang memiliki pompa pesannya pada satu utas dan penyajiannya di alur lain, aplikasi mungkin ingin mengubah mode. Utas pompa pesan memberi tahu utas penyajian untuk mengubah mode, dan menunggu hingga perubahan mode selesai. Namun, utas penyajian memanggil fungsi DXGI, yang pada gilirannya memanggil SendMessage, yang memblokir hingga pompa pesan memproses pesan. Kebuntuan terjadi karena kedua utas sekarang diblokir, dan sedang menunggu satu sama lain. Untuk menghindari hal ini, jangan pernah memblokir pompa pesan. Jika blok tidak dapat ditolak, maka semua interaksi DXGI harus terjadi pada utas yang sama dengan pompa pesan.

Gamma dan DXGI

Meskipun gamma mungkin paling baik ditangani di Direct3D 10.x atau Direct3D 11.x dengan menggunakan tekstur SRGB, ramp gamma masih dapat berguna bagi pengembang yang menginginkan nilai gamma yang berbeda dari 2.2 atau yang menggunakan format target render yang tidak mendukung SRGB. Waspadai dua masalah saat mengatur gamma ramp melalui DXGI. Masalah pertama adalah bahwa nilai ramp yang diteruskan ke IDXGIOutput::SetGammaControl adalah nilai float, bukan nilai WORD . Selain itu, pastikan kode yang di-port dari Direct3D 9 tidak mencoba mengonversi ke nilai WORD sebelum meneruskan kode ini ke SetGammaControl.

Masalah kedua adalah bahwa, setelah berubah ke mode layar penuh, SetGammaControl mungkin tidak tampak berfungsi, tergantung pada objek IDXGIOutput yang digunakan. Saat mengubah ke mode layar penuh, DXGI membuat objek output baru, dan menggunakan objek untuk semua operasi berikutnya pada output. Jika memanggil SetGammaControl pada output yang dijumlahkan sebelum pengalihan mode layar penuh, panggilan tidak diarahkan ke output yang digunakan DXGI saat ini. Untuk menghindari hal ini, panggil IDXGISwapChain::GetContainingOutput untuk mendapatkan output saat ini, lalu panggil SetGammaControl keluaran ini untuk mendapatkan perilaku yang benar.

Untuk informasi tentang menggunakan koreksi gamma, lihat Menggunakan koreksi gamma.

DXGI 1.1

Runtime Direct3D 11 yang disertakan dalam Windows 7 dan diinstal ke Windows Vista menyertakan DXGI versi 1.1. Pembaruan ini menambahkan definisi untuk sejumlah format baru (terutama BGRA, bias X2 10-bit, dan kompresi tekstur BC6H dan BC7 Direct3D 11), serta versi baru pabrik DXGI dan antarmuka adapter (CreateDXGIFactory1, IDXGIFactory1, IDXGIAdapter1) untuk menghitung koneksi desktop jarak jauh.

Saat Anda menggunakan Direct3D 11, runtime akan menggunakan DXGI 1.1 secara default saat memanggil D3D11CreateDevice atau D3D11CreateDeviceAndSwapChain dengan pointer NULL IDXGIAdapter . Pencampuran penggunaan DXGI 1.0 dan DXGI 1.1 dalam proses yang sama tidak didukung. Mencampur instans objek DXGI dari pabrik yang berbeda dalam proses yang sama juga tidak didukung. Oleh karena itu, ketika Anda menggunakan DirectX 11, setiap penggunaan eksplisit antarmuka DXGI menggunakan IDXGIFactory1 yang dibuat oleh entry-point CreateDXGIFactory1 di "DXGI.DLL" untuk memastikan aplikasi selalu menggunakan DXGI 1.1.

DXGI 1.2

Runtime Direct3D 11.1 yang disertakan dalam Windows 8 juga menyertakan DXGI versi 1.2.

DXGI 1.2 memungkinkan fitur-fitur ini:

  • penyajian stereo

  • Format 16 bit per piksel

    • DXGI_FORMAT_B5G6R5_UNORM dan DXGI_FORMAT_B5G5R5A1_UNORM sekarang didukung penuh
    • format DXGI_FORMAT_B5G5R5A1_UNORM baru ditambahkan
  • format video

  • antarmuka DXGI baru

Untuk informasi selengkapnya tentang fitur DXGI 1.2, lihat Peningkatan DXGI 1.2.