Objek aplikasi dan DirectX

Platform Windows Universal (UWP) dengan game DirectX tidak menggunakan banyak elemen dan objek antarmuka pengguna UI Windows. Sebaliknya, karena berjalan pada tingkat yang lebih rendah di tumpukan Windows Runtime, mereka harus beroperasi dengan kerangka kerja antarmuka pengguna dengan cara yang lebih mendasar: dengan mengakses dan beroperasi dengan objek aplikasi secara langsung. Pelajari kapan dan bagaimana interoperasi ini terjadi, dan bagaimana Anda, sebagai pengembang DirectX, dapat secara efektif menggunakan model ini dalam pengembangan aplikasi UWP Anda.

Lihat glosarium grafik Direct3D untuk informasi tentang istilah atau konsep grafis yang tidak dikenal yang Anda temui saat membaca.

Namespace antarmuka pengguna inti yang penting

Pertama, mari kita catat namespace Windows Runtime yang harus Anda sertakan (dengan menggunakan) di aplikasi UWP Anda. Kami masuk ke rincian dalam sedikit.

Catatan

Jika Anda tidak mengembangkan aplikasi UWP, gunakan komponen antarmuka pengguna yang disediakan di pustaka dan namespace khusus JavaScript atau XAML alih-alih jenis yang disediakan di namespace layanan ini.

Objek aplikasi Windows Runtime

Di aplikasi UWP, Anda ingin mendapatkan jendela dan penyedia tampilan tempat Anda bisa mendapatkan tampilan dan tempat Anda dapat menghubungkan rantai pertukaran (buffer tampilan Anda). Anda juga dapat menghubungkan tampilan ini ke dalam peristiwa khusus jendela untuk aplikasi yang sedang berjalan. Untuk mendapatkan jendela induk untuk objek aplikasi, yang ditentukan oleh jenis CoreWindow , buat jenis yang mengimplementasikan IFrameworkViewSource. Untuk contoh kode C++/WinRT yang menunjukkan cara mengimplementasikan IFrameworkViewSource, lihat Interoperaksi asli komposisi dengan DirectX dan Direct2D.

Berikut adalah serangkaian langkah dasar untuk mendapatkan jendela menggunakan kerangka kerja antarmuka pengguna inti.

  1. Buat jenis yang mengimplementasikan IFrameworkView. Ini adalah pandangan Anda.

    Dalam jenis ini, tentukan:

    • Metode Inisialisasi yang mengambil instans CoreApplicationView sebagai parameter. Anda bisa mendapatkan instans jenis ini dengan memanggil CoreApplication.CreateNewView. Objek aplikasi memanggilnya saat aplikasi diluncurkan.
    • Metode SetWindow yang mengambil instans CoreWindow sebagai parameter. Anda bisa mendapatkan instans jenis ini dengan mengakses properti CoreWindow pada instans CoreApplicationView baru Anda.
    • Metode Muat yang mengambil string untuk titik entri sebagai parameter satu-satu. Objek aplikasi menyediakan string titik entri saat Anda memanggil metode ini. Di sinilah Anda menyiapkan sumber daya. Anda membuat sumber daya perangkat di sini. Objek aplikasi memanggilnya saat aplikasi diluncurkan.
    • Metode Jalankan yang mengaktifkan objek CoreWindow dan memulai dispatcher peristiwa jendela. Objek aplikasi memanggilnya saat proses aplikasi dimulai.
    • Metode Batalkan diinisialisasi yang membersihkan sumber daya yang disiapkan dalam panggilan ke Muat. Objek aplikasi memanggil metode ini saat aplikasi ditutup.
  2. Buat jenis yang mengimplementasikan IFrameworkViewSource. Ini adalah penyedia tampilan Anda.

    Dalam jenis ini, tentukan:

    • Metode bernama CreateView yang mengembalikan instans implementasi IFrameworkView Anda, seperti yang dibuat di Langkah 1.
  3. Teruskan instans penyedia tampilan ke CoreApplication.Run dari utama.

Dengan ingat dasar-dasar tersebut, mari kita lihat lebih banyak opsi yang harus Anda perlukan untuk memperluas pendekatan ini.

Jenis antarmuka pengguna inti

Berikut adalah jenis antarmuka pengguna inti lainnya di Windows Runtime yang mungkin berguna bagi Anda:

Anda dapat menggunakan jenis ini untuk mengakses tampilan aplikasi, khususnya, bit yang menggambar konten jendela induk aplikasi, dan menangani peristiwa yang diaktifkan untuk jendela tersebut. Proses jendela aplikasi adalah aplikasi apartemen berulir tunggal (ASTA) yang terisolasi dan yang menangani semua panggilan balik.

Tampilan aplikasi Anda dihasilkan oleh penyedia tampilan untuk jendela aplikasi Anda, dan dalam banyak kasus akan diimplementasikan oleh paket kerangka kerja tertentu atau sistem itu sendiri, sehingga Anda tidak perlu menerapkannya sendiri. Untuk DirectX, Anda perlu menerapkan penyedia tampilan tipis, seperti yang dibahas sebelumnya. Ada hubungan 1-ke-1 tertentu antara komponen dan perilaku berikut:

  • Tampilan aplikasi, yang diwakili oleh jenis CoreApplicationView , dan yang menentukan metode untuk memperbarui jendela.
  • ASTA, atribusi yang menentukan perilaku utas aplikasi. Anda tidak dapat membuat instans jenis yang diatribusikan COM STA pada ASTA.
  • Penyedia tampilan, yang diperoleh aplikasi Anda dari sistem atau yang Anda terapkan.
  • Jendela induk, yang diwakili oleh jenis CoreWindow .
  • Sumber untuk semua peristiwa aktivasi. Tampilan dan jendela memiliki peristiwa aktivasi terpisah.

Singkatnya, objek aplikasi menyediakan pabrik penyedia tampilan. Ini membuat penyedia tampilan dan membuat instans jendela induk untuk aplikasi. Penyedia tampilan menentukan tampilan aplikasi untuk jendela induk aplikasi. Sekarang, mari kita bahas secara spesifik tampilan dan jendela induk.

Perilaku dan properti CoreApplicationView

CoreApplicationView mewakili tampilan aplikasi saat ini. Singleton aplikasi membuat tampilan aplikasi selama inisialisasi, tetapi tampilan tetap tidak aktif sampai diaktifkan. Anda bisa mendapatkan CoreWindow yang menampilkan tampilan dengan mengakses properti CoreApplicationView.CoreWindow di dalamnya, dan Anda dapat menangani peristiwa aktivasi dan penonaktifan untuk tampilan dengan mendaftarkan delegasi dengan peristiwa CoreApplicationView.Activated .

Perilaku dan properti CoreWindow

Jendela induk, yang merupakan instans CoreWindow , dibuat dan diteruskan ke penyedia tampilan saat objek aplikasi diinisialisasi. Jika aplikasi memiliki jendela untuk ditampilkan, aplikasi akan menampilkannya; jika tidak, itu hanya menginisialisasi tampilan.

CoreWindow menyediakan sejumlah peristiwa khusus untuk perilaku jendela input dan dasar. Anda dapat menangani peristiwa ini dengan mendaftarkan delegasi Anda sendiri dengannya.

Anda juga dapat memperoleh dispatcher peristiwa jendela untuk jendela dengan mengakses properti CoreWindow.Dispatcher , yang menyediakan instans CoreDispatcher.

Perilaku dan properti CoreDispatcher

Anda dapat menentukan perilaku utas pengiriman peristiwa untuk jendela dengan jenis CoreDispatcher . Pada jenis ini, ada satu metode yang sangat penting: metode CoreDispatcher.ProcessEvents , yang memulai pemrosesan peristiwa jendela. Memanggil metode ini dengan opsi yang salah untuk aplikasi Anda dapat menyebabkan semua jenis perilaku pemrosesan peristiwa yang tidak terduga.

Opsi CoreProcessEventsOption Deskripsi
CoreProcessEventsOption.ProcessOneAndAllPending Mengirim semua peristiwa yang tersedia saat ini dalam antrean. Jika tidak ada peristiwa yang tertunda, tunggu acara baru berikutnya.
CoreProcessEventsOption.ProcessOneIfPresent Mengirimkan satu peristiwa jika tertunda dalam antrean. Jika tidak ada peristiwa yang tertunda, jangan menunggu acara baru dinaikkan tetapi sebaliknya segera kembali.
CoreProcessEventsOption.ProcessUntilQuit Tunggu peristiwa baru dan mengirim semua peristiwa yang tersedia. Lanjutkan perilaku ini hingga jendela ditutup atau aplikasi memanggil metode Tutup pada instans CoreWindow .
CoreProcessEventsOption.ProcessAllIfPresent Mengirim semua peristiwa yang tersedia saat ini dalam antrean. Jika tidak ada peristiwa yang tertunda, segera kembalikan.

UWP yang menggunakan DirectX harus menggunakan opsi CoreProcessEventsOption.ProcessAllIfPresent untuk mencegah perilaku pemblokiran yang mungkin mengganggu pembaruan grafis.

Pertimbangan ASTA untuk dev DirectX

Objek aplikasi yang menentukan representasi run-time aplikasi YourUWP dan DirectX menggunakan model utas yang disebut Application Single-Threaded Apartment (ASTA) untuk menghosting tampilan UI aplikasi Anda. Jika Anda mengembangkan aplikasi UWP dan DirectX, Anda terbiasa dengan properti ASTA, karena utas apa pun yang Anda dikirim dari aplikasi UWP dan DirectX Anda harus menggunakan API Windows::System::Threading , atau menggunakan CoreWindow::CoreDispatcher. (Anda bisa mendapatkan objek CoreWindow untuk ASTA dengan memanggil CoreWindow::GetForCurrentThread dari aplikasi Anda.)

Hal terpenting yang harus Anda waspadai, sebagai pengembang aplikasi DirectX UWP, adalah Anda harus mengaktifkan utas aplikasi Anda untuk mengirimkan utas MTA dengan mengatur Platform::MTAThread di main().

[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
{
    auto myDXAppSource = ref new MyDXAppSource(); // your view provider factory 
    CoreApplication::Run(myDXAppSource);
    return 0;
}

Saat objek aplikasi untuk aplikasi DirectX UWP Anda diaktifkan, aplikasi akan membuat ASTA yang akan digunakan untuk tampilan UI. Utas ASTA baru memanggil ke pabrik penyedia tampilan Anda, untuk membuat penyedia tampilan untuk objek aplikasi Anda, dan sebagai hasilnya, kode penyedia tampilan Anda akan berjalan pada utas ASTA tersebut.

Selain itu, utas apa pun yang Anda spin off dari ASTA harus dalam MTA. Ketahuilah bahwa setiap utas MTA yang Anda spin off masih dapat membuat masalah reentrancy dan mengakibatkan kebuntuan.

Jika Anda memindahkan kode yang ada untuk dijalankan pada utas ASTA, ingatlah pertimbangan ini:

  • Primitif tunggu, seperti CoWaitForMultipleObjects, bertingkah berbeda dalam ASTA daripada di STA.

  • Perulangan modal panggilan COM beroperasi secara berbeda dalam ASTA. Anda tidak dapat lagi menerima panggilan yang tidak terkait saat panggilan keluar sedang berlangsung. Misalnya, perilaku berikut akan membuat kebuntuan dari ASTA (dan segera crash aplikasi):

    1. ASTA memanggil objek MTA dan melewati penunjuk antarmuka P1.
    2. Kemudian, ASTA memanggil objek MTA yang sama. Objek MTA memanggil P1 sebelum kembali ke ASTA.
    3. P1 tidak dapat memasukkan ASTA karena diblokir melakukan panggilan yang tidak terkait. Namun, utas MTA diblokir karena mencoba melakukan panggilan ke P1.

    Anda dapat mengatasinya dengan :

    • Menggunakan pola asinkron yang ditentukan dalam Pustaka Pola Paralel (PPLTasks.h)
    • Memanggil CoreDispatcher::P rocessEvents dari ASTA aplikasi Anda (utas utama aplikasi Anda) sesegera mungkin untuk memungkinkan panggilan sewenang-wenang.

    Meskipun demikian, Anda tidak dapat segera mengandalkan pengiriman panggilan yang tidak terkait ke ASTA aplikasi Anda. Untuk informasi selengkapnya tentang panggilan asinkron, baca Pemrograman asinkron di C++.

Secara keseluruhan, saat merancang aplikasi UWP Anda, gunakan CoreDispatcher untuk CoreWindow dan CoreDispatcher::P rocessEvents aplikasi Anda untuk menangani semua utas UI daripada mencoba membuat dan mengelola utas MTA Anda sendiri. Saat Anda memerlukan utas terpisah yang tidak dapat Anda tangani dengan CoreDispatcher, gunakan pola asinkron dan ikuti panduan yang disebutkan sebelumnya untuk menghindari masalah reentrancy.