Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini menjelaskan objek sinkronisasi pagar GPU yang dapat digunakan untuk sinkronisasi GPU-ke-GPU sejati dalam penjadwalan perangkat keras GPU tahap 2. Fitur ini didukung mulai windows 11, versi 24H2 (WDDM 3.2). Pengembang driver grafis harus terbiasa dengan penjadwalan perangkat keras WDDM 2.0 dan GPU tahap 1.
Objek sinkronisasi pagar yang dipantau WDDM 2.x
Objek sinkronisasi pagar WDDM 2.x yang dipantau mendukung operasi berikut:
- CPU menunggu pada nilai pagar yang dipantau, baik dengan:
- Polling menggunakan alamat virtual CPU (VA).
- Mengantre menunggu pemblokiran di dalam Dxgkrnl yang mendapat sinyal ketika CPU mengamati nilai pagar baru yang dipantau.
- Sinyal CPU dari nilai yang dipantau.
- Sinyal GPU dari nilai yang dipantau dengan menulis ke GPU VA pagar yang dipantau dan menaikkan pagar yang dipantau memberi sinyal interupsi untuk memberi tahu CPU tentang pembaruan nilai.
Apa yang tidak didukung adalah on-the-GPU asli menunggu nilai pagar yang dipantau. Sebagai gantinya, OS memegang pekerjaan GPU yang bergantung pada nilai yang ditunggu pada CPU. Ini hanya merilis pekerjaan ini ke GPU ketika nilai disinyalir.
Menambahkan objek sinkronisasi pagar asli GPU
Mulai WDDM 3.2, objek pagar yang dipantau diperluas untuk mendukung fitur tambahan berikut:
- GPU menunggu nilai pagar yang dipantau, yang memungkinkan sinkronisasi mesin ke mesin berkinerja tinggi tanpa memerlukan roundtrip CPU.
- Pemberitahuan interupsi bersyarat hanya untuk sinyal pagar GPU yang memiliki pelayan CPU. Fitur ini memungkinkan penghematan daya yang substansial dengan memungkinkan CPU memasuki status daya rendah saat semua pekerjaan GPU diantrekan.
- Penyimpanan nilai pagar dalam memori lokal GPU (dibandingkan dengan memori sistem).
Desain objek sinkronisasi pagar asli GPU
Diagram berikut mengilustrasikan arsitektur dasar objek pagar asli GPU, dengan fokus pada status objek sinkronisasi yang dibagikan antara CPU dan GPU.
:
Diagram ini mencakup dua komponen utama:
Nilai saat ini (disebut sebagai CurrentValue dalam artikel ini). Lokasi memori ini berisi nilai pagar 64-bit yang saat ini disinyalir. CurrentValue dipetakan dan dapat diakses oleh CPU (dapat ditulis dari mode kernel, dapat dibaca dari mode pengguna dan kernel) dan GPU (dapat dibaca dan ditulis menggunakan alamat virtual GPU). CurrentValue mengharuskan penulisan 64-bit menjadi atomik dari CPU dan sudut pandang GPU. Artinya, pembaruan untuk 32 bit tinggi dan rendah tidak dapat dikoyak dan harus terlihat pada saat yang sama. Konsep ini sudah ada di objek pagar yang dipantau yang ada.
Nilai yang dipantau (disebut sebagai MonitoredValue dalam artikel ini). Lokasi memori ini berisi nilai paling sedikit yang saat ini ditunggu oleh CPU yang dikurangi satu (1). MonitoredValue dipetakan dan dapat diakses oleh CPU (dapat dibaca dan ditulis dari mode kernel, tidak ada akses mode pengguna) dan GPU (dapat dibaca menggunakan GPU VA, tidak ada akses tulis). OS mempertahankan daftar pelayan CPU yang beredar untuk objek pagar tertentu, dan memperbarui MonitoredValue saat pelayan ditambahkan dan dihapus. Ketika tidak ada pelayan yang luar biasa, nilai diatur ke UINT64_MAX. Konsep ini baru untuk objek sinkronisasi pagar asli GPU.
Diagram berikutnya menggambarkan bagaimana Dxgkrnl melacak pelayan CPU yang luar biasa pada nilai pagar tertentu yang dipantau. Ini juga menunjukkan nilai pagar yang dipantau pada titik waktu tertentu. CurrentValue dan MonitoredValue keduanya adalah 41, yang berarti bahwa:
- GPU menyelesaikan semua tugas hingga nilai pagar 41.
- CPU tidak menunggu pada nilai pagar apa pun yang kurang dari atau sama dengan 41.
:
Diagram berikut menggambarkan bahwa prosesor manajemen konteks (CMP) GPU secara kondisional meningkatkan gangguan CPU hanya jika nilai pagar baru lebih besar dari nilai yang dipantau. Gangguan seperti itu berarti ada pelayan CPU luar biasa yang dapat puas dengan nilai yang baru ditulis.
:
Ketika CPU memproses gangguan ini, Dxgkrnl melakukan tindakan berikut seperti yang diilustrasikan dalam diagram berikutnya:
- Ini membuka blokir pelayan CPU yang telah puas dengan pagar yang baru ditulis.
- Ini memajukan nilai yang dipantau agar sesuai dengan nilai yang paling tidak terutang yang ditunggu pada nilai yang dikurangi oleh 1.
:
Penyimpanan memori fisik untuk nilai pagar saat ini dan yang dipantau
Untuk objek pagar tertentu, CurrentValue dan MonitoredValue disimpan di lokasi terpisah.
Objek pagar yang tidak dapat dibuat memiliki penyimpanan nilai pagar untuk objek pagar yang berbeda dalam proses yang sama yang dikemas dalam halaman memori yang sama. Nilai dikemas sesuai dengan nilai langkah yang ditentukan dalam batas KMD pagar asli yang dijelaskan nanti dalam artikel ini.
Objek pagar yang dapat dibagikan memiliki nilai saat ini dan yang dipantau yang ditempatkan di halaman memori yang tidak dibagikan dengan objek pagar lainnya.
Nilai saat ini
Nilai saat ini dapat berada baik dalam memori sistem atau memori lokal GPU, tergantung pada jenis pagar yang ditentukan oleh D3DDDI_NATIVEFENCE_TYPE.
Nilai saat ini untuk pagar adaptor silang selalu berada dalam memori sistem.
Ketika nilai saat ini disimpan dalam memori sistem, penyimpanan dialokasikan dari kumpulan memori sistem internal.
Ketika nilai saat ini disimpan dalam memori lokal, penyimpanan dialokasikan dari segmen memori yang ditentukan driver dalam D3DKMDT_FENCESTORAGESURFACEDATA.
Nilai yang dipantau
Nilai yang dipantau juga dapat berada di memori lokal sistem atau GPU, tergantung pada D3DDDI_NATIVEFENCE_TYPE.
Ketika nilai yang dipantau disimpan dalam memori sistem, OS mengalokasikan penyimpanan dari kumpulan memori sistem internal.
Ketika nilai yang dipantau disimpan dalam memori lokal, OS mengalokasikan penyimpanan dari segmen memori yang ditentukan driver dalam D3DKMDT_FENCESTORAGESURFACEDATA.
Ketika kondisi tunggu CPU OS berubah, ia memanggil panggilan balik DxgkDdiUpdateMonitoredValues KMD untuk menginstruksikan KMD untuk memperbarui nilai yang dipantau ke nilai tertentu.
Masalah Sinkronisasi
Mekanisme yang dijelaskan sebelumnya memiliki kondisi balapan yang melekat antara CPU dan pembacaan GPU dan penulisan nilai saat ini dan nilai yang dipantau. Jika perawatan khusus tidak dilakukan, masalah berikut dapat terjadi:
- GPU dapat membaca MonitoredValue kedaluarsa dan tidak menimbulkan gangguan seperti yang diharapkan oleh CPU.
- Mesin GPU dapat menulis CurrentValue yang lebih baru saat CMP berada di tengah-tengah memutuskan kondisi interupsi. CurrentValue yang lebih baru ini mungkin tidak memunculkan interupsi seperti yang diharapkan, atau mungkin tidak terlihat oleh CPU karena mengambil nilai saat ini.
Sinkronisasi dalam GPU antara mesin dan CMP
Untuk efisiensi, banyak GPU diskrit mengimplementasikan semantik sinyal pagar yang dipantau menggunakan status bayangan yang berada di memori lokal GPU antara:
Mesin GPU yang menjalankan aliran buffer perintah dan secara kondisional menaikkan sinyal perangkat keras ke CMP.
CMP GPU yang memutuskan apakah gangguan CPU harus dinaikkan.
Dalam hal ini, CMP perlu menyinkronkan akses memori dengan mesin GPU yang melakukan penulisan memori ke nilai pagar. Secara khusus, operasi memperbarui shadow MonitoredValue harus diurutkan dari sudut pandang CMP:
- Tulis MonitoredValue baru (penyimpanan GPU bayangan).
- Jalankan penghubung memori untuk menyinkronkan akses memori dengan mesin GPU.
- Baca CurrentValue:
- Jika CurrentValue>MonitoredValue, naikkan gangguan CPU.
- Jika CurrentValue<= MonitoredValue, jangan naikkan gangguan CPU.
Agar kondisi balapan ini diselesaikan dengan benar, sangat penting bahwa penghambat memori di langkah 2 berfungsi dengan baik. Tidak boleh ada operasi penulisan memori tertunda ke CurrentValue di langkah 3 yang berasal dari perintah yang belum melihat pembaruan MonitoredValue di langkah 1. Situasi ini akan menghasilkan gangguan jika pagar yang ditulis pada langkah 3 lebih besar dari nilai yang diperbarui pada langkah 1.
Sinkronisasi antara GPU dan CPU
CPU harus melakukan pembaruan MonitoredValue dan pembacaan CurrentValue dengan cara yang tidak kehilangan pemberitahuan interupsi untuk sinyal dalam penerbangan.
- OS harus memodifikasi MonitoredValue ketika pelayan CPU baru ditambahkan ke sistem, atau jika pelayan CPU yang ada dihentikan.
- OS memanggil DxgkDdiUpdateMonitoredValues untuk memberi tahu GPU tentang nilai baru yang dipantau.
- DxgkDdiUpdateMonitoredValue dijalankan pada tingkat interupsi perangkat dan dengan demikian disinkronkan dengan rutinitas layanan interupsi sinyal pagar yang dipantau (ISR).
- DxgkDdiUpdateMonitoredValue harus menjamin bahwa, setelah dikembalikan, CurrentValue yang dibaca oleh inti prosesor apa pun ditulis oleh GPU CMP setelah mengamati MonitoredValue baru.
- Setelah kembali dari DxgkDdiUpdateMonitoredValue, OS membuat ulang CurrentValue dan memenuhi semua pelayan yang tidak diblokir oleh CurrentValue baru.
CPU dapat diterima dengan sempurna untuk mengamati CurrentValue yang lebih baru daripada yang digunakan oleh GPU untuk memutuskan apakah akan meningkatkan gangguan. Situasi ini kadang-kadang akan mengakibatkan pemberitahuan interupsi yang tidak membuka blokir pelayan apa pun. Apa yang tidak dapat diterima adalah agar CPU tidak menerima pemberitahuan interupsi untuk pembaruan CurrentValue terbaru yang dipantau (yaitu, >.)
Mengkueri pengaktifan fitur pagar asli di OS
Driver harus meminta apakah fitur pagar asli diaktifkan di OS selama inisialisasi driver. Mulai WDDM 3.2, OS menggunakan antarmuka IsFeatureEnabled yang ditambahkan untuk mengontrol apakah fitur tertentu diaktifkan, termasuk fitur pagar asli.
Akibatnya, KMD harus mengimplementasikan antarmuka IsFeatureEnabled . Implementasi KMD harus mengkueri apakah OS telah mengaktifkan fitur DXGK_FEATURE_NATIVE_FENCE sebelum mengiklankan dukungan pagar asli di DXGK_VIDSCHCAPS. OS gagal menginisialisasi adaptor jika KMD mengiklankan dukungan pagar asli ketika OS belum mengaktifkan fitur.
Untuk informasi selengkapnya tentang antarmuka pengaktifan fitur, lihat Mengkueri dukungan dan pengaktifan fitur WDDM.
DDI untuk mengkueri pengaktifan fitur pagar asli
Antarmuka berikut diperkenalkan untuk KMD untuk mengkueri apakah OS mengaktifkan fitur pagar asli:
- DXGKCB_FEATURE_NATIVEFENCE_CAPS_1
- DXGKARGCB_FEATURE_NATIVEFENCE_CAPS_1
- DXGKCBINT_FEATURE_NATIVEFENCE_1
OS mengimplementasikan tabel antarmuka DXGKCB_FEATURE_NATIVEFENCE_CAPS_1 yang ditambahkan yang didedikasikan untuk versi 1 DXGK_FEATURE_NATIVE_FENCE. KMD harus mengkueri tabel antarmuka fitur ini untuk menentukan kemampuan OS. Dalam rilis OS mendatang, OS mungkin memperkenalkan versi tabel antarmuka ini di masa mendatang, yang merinci dukungan untuk kemampuan baru.
Contoh kode driver untuk dukungan kueri
Kode sampel berikut menunjukkan bagaimana driver diharapkan menggunakan fitur DXGK_FEATURE_NATIVE_FENCE di antarmuka DXGK_FEATURE_INTERFACE untuk dukungan kueri.
DXGK_FEATURE_INTERFACE FeatureInterface;
struct FEATURE_RESULT
{
bool Enabled;
DXGK_FEATURE_VERSION Version;
};
// Driver internal cache for state & version of queried features
struct FEATURE_STATE
{
struct
{
UINT NativeFenceEnabled : 1;
};
DXGK_FEATURE_VERSION NativeFenceVersion = 0;
// Interfaces
DXGKCBINT_FEATURE_NATIVEFENCE_1 NativeFenceInterface = {};
// Interface queried values
DXGKARGCB_FEATURE_NATIVEFENCE_CAPS_1 NativeFenceOSCaps1 = {};
};
// Helper function to query OS's feature enabled interface
FEATURE_RESULT IsFeatureEnabled(
DXGK_FEATURE_ID FeatureId
)
{
FEATURE_RESULT Result = {};
//
// If the feature interface functionality is available (e.g. supported by the OS)
//
DXGKARGCB_ISFEATUREENABLED2 Args = {};
Args.FeatureId = FeatureId;
if(NT_SUCCESS(FeatureInterface.IsFeatureEnabled(DxgkInterface.DeviceHandle, &Args)))
{
Result.Enabled = Args.Result.Enabled;
Result.Version = Args.Result.Version;
}
return Result;
}
// Actual code to query whether OS has enabled Native Fence support and corresponding OS caps
FEATURE_RESULT FeatureResult = IsFeatureEnabled(DXGK_FEATURE_NATIVE_FENCE);
FEATURE_STATE FeatureState = {};
FeatureState.NativeFenceEnabled = !!FeatureResult.Enabled;
if (FeatureResult.Enabled)
{
// Query OS caps for native fence feature, using the feature interface
DXGKARGCB_QUERYFEATUREINTERFACE QFIArgs = {};
QFIArgs.FeatureId = DXGK_FEATURE_NATIVE_FENCE;
QFIArgs.Interface = &FeatureState.NativeFenceInterface;
QFIArgs.InterfaceSize = sizeof(FeatureState.NativeFenceInterface);
QFIArgs.Version = FeatureResult.Version;
Status = FeatureInterface.QueryFeatureInterface(DxgkInterface.DeviceHandle, &QFIArgs);
if(NT_SUCCESS(Status))
{
FeatureState.NativeFenceVersion = FeatureResult.Version;
Status = FeatureState.NativeFenceInterface.GetOSCaps(&FeatureState.NativeFenceOSCaps1);
NT_ASSERT(NT_SUCCESS(Status));
}
else
{
// We should always succeed getting an interface from a successfully
// negotiated feature + version.
NT_ASSERT(FALSE);
}
}
Kemampuan pagar asli
Antarmuka berikut diperbarui atau diperkenalkan ke batas pagar asli kueri:
Bidang NativeGpuFence ditambahkan ke DXGK_VIDSCHCAPS. Jika OS mengaktifkan fitur DXGK_FEATURE_NATIVE_FENCE, driver dapat mendeklarasikan dukungan untuk fungsionalitas pagar GPU asli selama inisialisasi adaptor dengan mengatur DXGK_VIDSCHCAPS::NativeGpuFence bit ke 1.
DXGKQAITYPE_NATIVE_FENCE_CAPS ditambahkan ke DXGK_QUERYADAPTERINFOTYPE.
Dxgkrnl memaparkan fitur ini ke mode pengguna melalui D3DKMT_WDDM_3_1_CAPS yang sesuai yang ditambahkan ::NativeGpuFenceSupported structure/bit.
KMTQAITYPE_WDDM_3_1_CAPS ditambahkan ke KMTQUERYADAPTERINFOTYPE.
Entitas berikut ditambahkan untuk KMD untuk menunjukkan kemampuan dukungannya untuk fitur pagar GPU asli.
Struktur DXGK_NATIVE_FENCE_CAPS menjelaskan kemampuan pagar asli GPU. Ketika KMD mengatur bit MapToGpuSystemProcess struktur ini, KMD menginstruksikan OS untuk mencadangkan ruang alamat virtual GPU proses sistem untuk penggunaan CMP, dan untuk membuat pemetaan VA GPU ke ruang alamat tersebut untuk pagar asli CurrentValue dan MonitoredValue. VAS GPU ini kemudian diteruskan ke panggilan balik pembuatan pagar KMD sebagai DXGKARG_CREATENATIVEFENCE::CurrentValueSystemProcessGpuVa dan MonitoredValueSystemProcessGpuVa.
KMD mengembalikan struktur DXGK_NATIVE_FENCE_CAPS yang diisi ketika fungsi DxgkDdiQueryAdapterInfo dipanggil dengan jenis info adaptor kueri DXGKQAITYPE_NATIVE_FENCE_CAPS ditambahkan.
KMD DDI untuk membuat, membuka, menutup, dan menghancurkan objek pagar asli
DDI yang diimplementasikan KMD berikut diperkenalkan untuk membuat, membuka, menutup, dan menghancurkan objek pagar asli. Dxgkrnl memanggil DDI ini atas nama komponen mode pengguna. Dxgkrnl memanggil mereka hanya jika OS mengaktifkan fitur DXGK_FEATURE_NATIVE_FENCE .
- DxgkDdiCreateNativeFence/DXGKARG_CREATENATIVEFENCE
- DxgkDdiOpenNativeFence/DXGKARG_OPENNATIVEFENCE
- DxgkDdiCloseNativeFence/DXGKARG_CLOSENATIVEFENCE
- DxgkDdiDestroyNativeFence/DXGKARG_DESTROYNATIVEFENCE
DDI berikut diperbarui untuk mendukung objek pagar asli:
Anggota berikut ditambahkan ke DRIVER_INITIALIZATION_DATA. Driver yang mendukung objek pagar GPU asli harus mengimplementasikan fungsi dan menyediakan Dxgkrnl dengan pointer ke objek tersebut melalui struktur ini.
- PDXGKDDI_CREATENATIVEFENCE DxgkDdiCreateNativeFence (ditambahkan dalam WDDM 3.1)
- PDXGKDDI_DESTROYNATIVEFENCE DxgkDdiDestroyNativeFence (ditambahkan dalam WDDM 3.1)
- PDXGKDDI_OPENNATIVEFENCE DxgkDdiCreateNativeFence (ditambahkan dalam WDDM 3.2)
- PDXGKDDI_CLOSENATIVEFENCE DxgkDdiCloseNativeFence (ditambahkan dalam WDDM 3.2)
- PDXGKDDI_SETNATIVEFENCELOGBUFFER DxgkDdiSetNativeFenceLogBuffer (ditambahkan dalam WDDM 3.2)
- PDXGKDDI_UPDATENATIVEFENCELOGS DxgkDdiUpdateNativeFenceLogs (ditambahkan dalam WDDM 3.2)
Handel global dan lokal untuk pagar bersama
Bayangkan proses A menciptakan pagar asli bersama dan proses B kemudian membuka pagar ini.
Ketika proses A membuat pagar asli bersama, Dxgkrnl memanggil DxgkDdiCreateNativeFence dengan handel driver adapter tempat pagar ini dibuat. Handel pagar yang dibuat dan dikembalikan dalam hGlobalNativeFence adalah handel pagar global.
Dxgkrnl kemudian menindaklanjuti dengan panggilan ke DxgkDdiOpenNativeFence untuk membuka proses handel lokal khusus A (hLocalNativeFenceA).
Ketika proses B membuka pagar asli bersama yang sama, Dxgkrnl memanggil DxgkDdiOpenNativeFence untuk membuka proses handel lokal khusus B (hLocalNativeFenceB).
Jika proses A menghancurkan instans pagar asli bersamanya, Dxgkrnl melihat bahwa masih ada referensi tertunda ke pagar global ini, jadi hanya memanggil DxgkDdiCloseNativeFence (hLocalNativeFenceA) bagi pengemudi untuk membersihkan proses struktur khusus A. Handel hGlobalNativeFence masih ada.
Ketika proses B menghancurkan instans pagarnya, Dxgkrnl memanggil DxgkDdiCloseNativeFence (hLocalNativeFenceB) dan kemudian DxgkDdiDestroyNativeFence (hGlobalNativeFence) untuk memungkinkan KMD menghancurkan data pagar globalnya.
Pemetaan VA GPU di ruang alamat proses halaman untuk penggunaan CMP
KMD mengatur batas DXGK_NATIVE_FENCE_CAPS::MapToGpuSystemProcess pada perangkat keras yang mengharuskan GPU pagar asli VPU juga dipetakan ke ruang alamat proses penomoran GPU. Bit MapToGpuSystemProcess yang ditetapkan menginstruksikan OS untuk membuat pemetaan VA GPU di ruang alamat proses penomoran untuk CurrentValue dan MonitoredValue pagar asli untuk digunakan oleh CMP. VAs GPU ini kemudian diteruskan ke DxgkDdiCreateNativeFence sebagai DXGKARG_CREATENATIVEFENCE::CurrentValueSystemProcessGpuVa dan MonitoredValueSystemProcessGpuVa.
API kernel D3DKMT untuk membuat, membuka, dan menghancurkan pagar asli
API mode kernel D3DKMT berikut diperkenalkan untuk membuat dan membuka objek pagar asli.
- D3DKMTCreateNativeFence / D3DKMT_CREATENATIVEFENCE
- D3DKMTOpenNativeFenceFromNTHandle / D3DKMT_OPENNATIVEFENCEFROMNTHANDLE
Dxgkrnl memanggil fungsi D3DKMTDestroySynchronizationObject yang ada untuk menutup dan menghancurkan (bebas) objek pagar asli yang ada.
Struktur dukungan dan enumerasi yang diperkenalkan atau diperbarui meliputi:
- D3DDDI_NATIVEFENCEINFO
- D3DDDI_NATIVEFENCE_TYPE
- D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS
- D3DDDI_NATIVEFENCE_MAPPING
DDI untuk mendukung penempatan nilai pagar asli dalam memori lokal
DDI berikut ditambahkan atau diubah untuk mendukung penempatan nilai pagar asli dalam memori lokal:
Struktur D3DKMDT_FENCESTORAGESURFACEDATA ditambahkan.
Pagar asli MonitoredValue dan CurrentValue dari jenis pagar asli D3DDDI_NATIVEFENCE_TYPE_INTRA_GPU dapat ditempatkan dalam memori perangkat lokal. Untuk melakukannya, OS akan meminta driver untuk menentukan segmen memori tempat penyimpanan pagar harus ditempatkan. DxgkDdiGetStandardAllocation diperluas untuk memberikan informasi tersebut.
D3DKMDT_STANDARDALLOCATION_FENCESTORAGE ditambahkan ke DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA.
Menunjukkan pagar kemajuan asli untuk antrean perangkat keras
Pembaruan berikut diperkenalkan untuk menunjukkan objek progres progres antrean perangkat keras asli:
Bendera NativeProgressFence ditambahkan untuk panggilan ke DxgkDdiCreateHwQueue.
- Pada sistem yang didukung, OS memperbarui pagar kemajuan antrean perangkat keras ke pagar asli. Ketika OS menetapkan NativeProgressFence, itu menunjukkan kepada KMD bahwa DXGKARG_CREATEHWQUEUE::hHwQueueProgressFence menangani titik ke handel driver objek pagar GPU asli yang sebelumnya dibuat menggunakan DxgkDdiCreateNativeFence.
Pagar asli memberi sinyal interupsi
Perubahan berikut dilakukan pada mekanisme interupsi untuk mendukung interupsi sinyal pagar asli:
Enum DXGK_INTERRUPT_TYPE diperbarui untuk memiliki jenis interupsi DXGK_INTERRUPT_NATIVE_FENCE_SIGNALED.
Struktur DXGKARGCB_NOTIFY_INTERRUPT_DATA diperbarui untuk menyertakan struktur NativeFenceSignaled untuk menunjukkan pagar asli yang memberi sinyal interupsi
NativeFenceSignaled digunakan untuk memberi tahu OS bahwa satu set objek GPU pagar asli yang dipantau oleh CPU diberi sinyal pada mesin GPU. Jika GPU dapat menentukan subset objek yang tepat dengan pelayan CPU aktif, GPU meneruskan subset ini melalui pSignaledNativeFenceArray. Handel dalam array ini harus valid hGlobalNativeFence menangani Dxgkrnl yang diteruskan ke KMD di DxgkDdiCreateNativeFence. Meneruskan handel ke objek pagar asli yang hancur menyebabkan pemeriksaan bug.
Struktur DXGKCB_NOTIFY_INTERRUPT_DATA_FLAGS diperbarui untuk menyertakan anggota EvaluateLegacyMonitoredFences .
GPU dapat melewati NULL pSignaledNativeFenceArray dalam kondisi berikut:
- GPU tidak dapat menentukan subset objek yang tepat dengan pelayan CPU aktif.
- Beberapa gangguan sinyal diciutkan bersama-sama sehingga sulit untuk menentukan set yang disinyalir dengan pelayan aktif.
Nilai NULL menginstruksikan OS untuk memindai semua pelayan objek pagar GPU asli yang luar biasa.
Kontrak antara OS dan driver adalah: jika OS memiliki pelayan CPU aktif (seperti yang dinyatakan oleh MonitoredValue), dan mesin GPU memberi sinyal objek ke nilai yang memerlukan gangguan CPU, GPU harus mengambil salah satu tindakan berikut:
- Sertakan handel pagar asli ini di pSignaledNativeFenceArray.
- Meningkatkan interupsi NativeFenceSignaled dengan NULL pSignaledNativeFenceArray.
Secara default, ketika KMD meningkatkan gangguan ini dengan NULL pSignaledNativeFenceArray, Dxgkrnl hanya memindai semua pelayan pagar asli yang tertunda dan tidak memindai pelayan pagar lama yang dipantau. Pada perangkat keras yang tidak dapat membedakan antara DXGK_INTERRUPT_MONITORED_FENCE_SIGNALED warisan dan DXGK_INTERRUPT_NATIVE_FENCE_SIGNALED, KMD selalu dapat menaikkan hanya DXGK_INTERRUPT_NATIVE_FENCE_SIGNALED yang diperkenalkan dengan pSignaledNativeFenceArray = NULL dan EvaluateLegacyMonitoredFences = 1, yang menunjukkan kepada OS untuk memindai semua pelayan (pelayan pagar terpantau warisan & pelayan pagar asli).
Menginstruksikan KMD untuk memperbarui batch nilai
Antarmuka berikut diperkenalkan untuk menginstruksikan KMD untuk memperbarui batch nilai saat ini atau yang dipantau:
DxgkDdiUpdateCurrentValuesFromCpu / DXGKARG_UPDATECURRENTVALUESFROMCPU
DxgkDdiUpdateMonitoredValues / DXGKARG_UPDATEMONITOREDVALUES
Pagar asli lintas adaptor
OS harus mendukung pembuatan pagar asli lintas adaptor karena aplikasi DX12 yang ada membuat dan menggunakan pagar yang dipantau lintas adaptor. Jika antrean dan penjadwalan yang mendasar untuk aplikasi ini dialihkan ke pengiriman mode pengguna, maka pagar yang dipantau juga harus dialihkan ke pagar asli (antrean mode pengguna tidak dapat mendukung pagar yang dipantau).
Pagar adaptor silang harus dibuat dengan jenis D3DDDI_NATIVEFENCE_TYPE_DEFAULT. Jika tidak, D3DKMTCreateNativeFence gagal.
Semua GPU berbagi salinan penyimpanan CurrentValue yang sama, yang selalu dialokasikan dalam memori sistem. Ketika runtime membuat pagar asli lintas adaptor pada GPU1 dan membukanya pada GPU2, pemetaan VA GPU pada kedua GPU menunjuk ke penyimpanan fisik CurrentValue yang sama.
Setiap GPU mendapatkan salinan MonitoredValue sendiri. Oleh karena itu, penyimpanan MonitoredValue dapat dialokasikan dalam memori sistem atau memori lokal.
Pagar asli lintas adaptor harus menyelesaikan kondisi di mana GPU1 menunggu pagar asli yang disinyalir GPU2. Saat ini, tidak ada konsep sinyal GPU-ke-GPU; oleh karena itu, OS secara eksplisit menyelesaikan kondisi ini dengan memberi sinyal GPU1 dari CPU. Sinyal ini dilakukan dengan mengatur MonitoredValue untuk pagar lintas adaptor ke 0 selama masa pakainya. Kemudian, ketika GPU2 menandakan pagar asli, GPU juga meningkatkan gangguan CPU, memungkinkan Dxgkrnl untuk memperbarui CurrentValue pada GPU1 (menggunakan DxgkDdiUpdateCurrentValuesFromCpu dengan bendera NotificationOnly diatur TRUE) dan membuka blokir setiap pelayan CPU/GPU yang tertunda dari GPU tersebut.
Meskipun MonitoredValue selalu 0 untuk pagar asli lintas adaptor, tunggu dan sinyal yang dikirimkan pada GPU yang sama masih mendapat manfaat dari lebih cepat pada sinkronisasi GPU. Namun, manfaat daya dari gangguan CPU yang berkurang hilang karena gangguan CPU akan dinaikkan tanpa syarat, bahkan jika tidak ada pelayan CPU atau pelayan pada GPU lain. Trade-off ini dibuat untuk menjaga desain dan biaya implementasi pagar asli lintas adaptor sederhana.
OS mendukung skenario di mana objek pagar asli dibuat pada GPU1 dan dibuka pada GPU2, di mana GPU1 mendukung fitur dan GPU2 tidak. Objek pagar dibuka sebagai MonitoredFence biasa pada GPU2.
OS mendukung skenario di mana objek pagar yang dipantau reguler dibuat pada GPU1 dan dibuka sebagai pagar asli pada GPU2, yang mendukung fitur tersebut. Objek pagar dibuka sebagai pagar asli pada GPU2.
Kombinasi tunggu/sinyal lintas adaptor
Tabel dalam subbagian berikut mengambil contoh sistem iGPU dan dGPU, dan mencantumkan berbagai konfigurasi yang mungkin untuk tunggu/sinyal pagar asli dari CPU/GPU. Dua kasus berikut dipertimbangkan:
- Kedua GPU mendukung pagar asli.
- iGPU tidak mendukung pagar asli, tetapi dGPU mendukung pagar asli.
Skenario kedua juga mirip dengan kasus di mana kedua GPU mendukung pagar asli, tetapi tunggu/sinyal pagar asli dikirimkan ke antrean mode kernel pada iGPU.
Tabel harus dibaca dengan memilih sepasang tunggu dan sinyal dari kolom, misalnya WaitFromGPU - SignalFromGPU atau WaitFromGPU - SignalFromCPU, et cetera.
Skenario 1
Dalam Skenario 1, dGPU dan iGPU mendukung pagar asli.
| iGPU WaitFromGPU (oleh karena itu, 10) | WaitFromCPU iGPU (karenanya, 10) | dGPU SignalFromGpu (oleh karena itu, 10) | dGPU SignalFromCpu(hFence, 10) |
|---|---|---|---|
| UMD menyisipkan tunggu karenanya CurrentValue == 10 instruksi dalam buffer perintah | Runtime memanggil D3DKMTWaitForSynchronizationObjectFromCpu | ||
| VidSch melacak objek sinkronisasi ini dalam daftar pelayan CPU pagar aslinya | |||
| UMD menyisipkan instruksi tulis hFence CurrentValue = 10 sinyal di buffer perintah | Runtime memanggil D3DKMTSignalSynchronizationObjectFromCpu | ||
| VidSch menerima ISR bertanda pagar asli ketika CurrentValue ditulis (karena MonitoredValue == 0 selalu) | VidSch memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, 10) | ||
| VidSch menyebarluaskan sinyal (oleh karena itu, 10) ke iGPU | VidSch menyebarkan sinyal (karenanya, 10) ke iGPU | ||
| VidSch menerima sinyal yang disebarkan dan memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, NotificationOnly=TRUE) | VidSch menerima sinyal yang disebarkan dan memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, NotificationOnly=TRUE) | ||
| KMD memunculkan ulang daftar eksekusi untuk membuka blokir saluran HW yang menunggu di hFence | VidSch membuka blokir kondisi tunggu CPU dengan memberi sinyal KEVENT |
Skenario 2a
Dalam Skenario 2a, iGPU tidak mendukung pagar asli tetapi dGPU melakukannya. Tunggu dikirimkan pada iGPU dan sinyal dikirimkan pada dGPU.
| iGPU WaitFromGPU (oleh karena itu, 10) | WaitFromCPU iGPU (karenanya, 10) | dGPU SignalFromGpu (oleh karena itu, 10) | dGPU SinyalDariCpu(hFence, 10) |
|---|---|---|---|
| Runtime memanggil D3DKMTWaitForSynchronizationObjectFromGpu | Runtime memanggil D3DKMTWaitForSynchronizationObjectFromCpu | ||
| VidSch melacak objek sinkronisasi ini dalam daftar tunggu pagar yang dipantau | VidSch melacak objek sinkronisasi ini di kepala daftar pelayan CPU pagar yang dipantau | ||
| UMD menyisipkan instruksi tulis hFence CurrentValue = 10 sinyal dalam buffer perintah | Runtime memanggil D3DKMTSignalSynchronizationObjectFromCpu | ||
| VidSch menerima NativeFenceSignaledISR ketika CurrentValue ditulis (karena MV == 0 selalu) | VidSch memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, 10) | ||
| VidSch menyebarkan sinyal (karenanya, 10) ke iGPU | VidSch menyebarkan sinyal (karenanya, 10) ke iGPU | ||
| VidSch menerima sinyal yang disebarkan dan mengamati nilai pagar baru | VidSch menerima sinyal yang disebarkan dan mengamati nilai pagar baru | ||
| VidSch memindai daftar tunggu pagar yang dipantau dan membuka blokir konteks perangkat lunak | VidSch memindai kepala daftar pelayan CPU pagar yang dipantau dan membuka blokir CPU tunggu dengan memberi sinyal KEVENT |
Skenario 2b
Dalam Skenario 2b, dukungan pagar asli tetap sama (iGPU tidak mendukung, dGPU tidak). Kali ini, sinyal dikirimkan pada iGPU dan tunggu dikirimkan pada dGPU.
| iGPU SignalFromGPU (oleh karena itu, 10) | iGPU SignalFromCPU (karenanya, 10) | dGPU WaitFromGpu (oleh karena itu, 10) | dGPU WaitFromCpu(hFence, 10) |
|---|---|---|---|
| UMD menyisipkan tunggu maka CurrentValue == 10 instruksi dalam buffer perintah | Runtime memanggil D3DKMTWaitForSynchronizationObjectFromCpu | ||
| VidSch melacak objek sinkronisasi ini dalam daftar pelayan CPU pagar aslinya | |||
| UMD memanggil D3DKMTSignalSynchronizationObjectFromGpu | UMD memanggil D3DKMTSignalSynchronizationObjectFromCpu | ||
| Ketika paket berada di kepala konteks perangkat lunak, VidSch memperbarui nilai pagar langsung dari CPU | VidSch memperbarui nilai pagar langsung dari CPU | ||
| VidSch menyebarluaskan sinyal (oleh karena itu, 10) ke dGPU | VidSch menyebarluaskan sinyal (oleh karena itu, 10) ke dGPU | ||
| VidSch menerima sinyal yang disebarkan dan memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, NotificationOnly=TRUE) | VidSch menerima sinyal yang disebarkan dan memanggil DxgkDdiUpdateCurrentValuesFromCpu(hFence, NotificationOnly=TRUE) | ||
| KMD memunculkan ulang daftar eksekusi untuk membuka blokir saluran HW yang menunggu di hFence | VidSch membuka blokir kondisi tunggu CPU dengan memberi sinyal KEVENT |
Sinyal adaptor silang GPU-ke-GPU di masa mendatang
Seperti yang dijelaskan dalam Masalah sinkronisasi, untuk pagar asli lintas adaptor, kami kehilangan penghematan daya karena gangguan CPU dinaikkan tanpa syarat.
Dalam rilis mendatang, OS akan mengembangkan infrastruktur untuk memungkinkan sinyal GPU pada satu GPU mengganggu GPU lain dengan menulis ke memori bel pintu umum, memungkinkan GPU lain untuk bangun, memproses run-list dan membuka blokir antrean HW yang siap.
Tantangan untuk pekerjaan ini adalah merancang:
- Memori bel pintu umum.
- Payload atau handel cerdas yang dapat ditulis GPU ke bel pintu yang memungkinkan GPU lain menentukan pagar mana yang disinyalir sehingga hanya dapat memindai subset HWQueues.
Dengan sinyal adaptor silang seperti itu, GPU mungkin bahkan dapat berbagi salinan penyimpanan pagar asli yang sama (alokasi lintas adaptor format linier, mirip dengan alokasi pemindaian lintas adaptor) tempat semua GPU membaca dan menulis.
Desain buffer log pagar asli
Dengan pagar asli dan pengiriman mode pengguna, Dxgkrnl tidak memiliki visibilitas ketika GPU asli menunggu dan sinyal yang diantrekan dari UMD tidak diblokir pada GPU untuk HWQueue tertentu. Dengan pagar asli, pagar yang dipantau memberi sinyal interupsi dapat ditekan untuk pagar tertentu.
:
Cara untuk membuat ulang operasi pagar seperti yang ditunjukkan pada gambar GPUView ini diperlukan. Kotak merah muda gelap adalah sinyal dan kotak merah muda terang sedang menunggu. Setiap kotak dimulai ketika operasi dikirimkan pada CPU ke Dxgkrnl dan berakhir ketika Dxgkrnl menyelesaikan operasi pada CPU. Dengan cara ini kita dapat mempelajari seluruh masa pakai perintah.
Jadi, pada tingkat tinggi, kondisi per HWQueue yang diperlukan untuk dicatat adalah:
| Kondisi | Makna |
|---|---|
| FENCE_WAIT_QUEUED | Tanda Waktu CPU saat UMD menyisipkan instruksi Tunggu GPU dalam antrean perintah |
| FENCE_SIGNAL_QUEUED | Tanda Waktu CPU saat UMD menyisipkan instruksi sinyal GPU dalam antrean perintah |
| FENCE_SIGNAL_EXECUTED | Tanda waktu GPU saat perintah sinyal dijalankan pada GPU untuk HWQueue |
| FENCE_WAIT_UNBLOCKED | Tanda waktu GPU saat kondisi tunggu terpenuhi pada GPU dan HWQueue tidak diblokir |
DDIs buffer log pagar asli
DDI, struktur, dan enum berikut diperkenalkan untuk mendukung buffer log pagar asli:
- DxgkDdiSetNativeFenceLogBuffer / DXGKARG_SETNATIVEFENCELOGBUFFER
- DxgkDdiUpdateNativeFenceLogs / DXGKARG_UPDATENATIVEFENCELOGS
- Buffer log yang berisi header dan array entri log. Header mengidentifikasi apakah entri adalah untuk tunggu atau sinyal, dan setiap entri mengidentifikasi jenis operasi (dijalankan atau tidak diblokir):
Desain buffer log dimaksudkan untuk antrean pengiriman pagar dan mode pengguna asli di mana payload buffer log ditulis oleh mesin GPU/CMP, tanpa keterlibatan dari Dxgkrnl atau KMD. Oleh karena itu, UMD akan menyisipkan instruksi saat menghasilkan buffer perintah tunggu/sinyal, memprogram GPU untuk menulis payload buffer log ke dalam entri buffer log pada eksekusi. Untuk pengiriman mode non-pengguna (yaitu, antrean mode kernel), sinyal dan tunggu adalah perintah perangkat lunak di dalam Dxgkrnl, jadi kami sudah mengetahui tanda waktu dan detail lain dari operasi ini dan kami tidak memerlukan perangkat keras/KMD untuk memperbarui buffer log. Untuk antrean mode kernel tersebut, Dxgkrnl tidak akan membuat buffer log.
Mekanisme buffer log
Dxgkrnl mengalokasikan dua buffer log 4 KB khusus per HWQueue.
- Satu untuk pencatatan menunggu.
- Satu untuk sinyal pengelogan.
Buffer log ini memiliki pemetaan untuk VA CPU mode kernel (LogBufferCpuVa), VA GPU dalam ruang alamat proses (LogBufferGpuVa), dan CMP VA (LogBufferSystemProcessGpuVa), sehingga dapat dibaca/ditulis ke KMD, mesin GPU, dan CMP. Dxgkrnl memanggil DxgkDdiSetNativeFenceLogBuffer dua kali: sekali untuk mengatur buffer log untuk pencatatan tunggu dan sekali untuk mengatur buffer log untuk sinyal pengelogan.
Segera setelah UMD menyisipkan instruksi tunggu atau sinyal pagar asli dalam daftar perintah, umD juga menyisipkan perintah yang menginstruksikan GPU untuk menulis payload pada entri tertentu ke dalam buffer log.
Setelah mesin GPU menjalankan operasi pagar, mesin melihat instruksi UMD untuk menulis payload ke entri tertentu ke dalam buffer log. Selain itu, GPU juga menulis FenceEndGpuTimestamp saat ini ke dalam entri buffer log ini.
Meskipun UMD tidak dapat mengakses buffer log yang dapat diakses GPU, UMD mengontrol perkembangan buffer log. Artinya, UMD menentukan entri gratis berikutnya untuk menulis ke, jika ada, dan memprogram GPU dengan informasi ini. Saat GPU menulis ke buffer log, GPU akan meningkatkan nilai FirstFreeEntryIndex di header log. UMD harus memastikan bahwa penulisan ke entri log meningkat secara monoton.
Pertimbangkan skenario berikut:
- Ada dua HWQueues, HWQueueA dan HWQueueB, dengan buffer log pagar yang sesuai dengan VAs GPU FenceLogA dan FenceLogB. HWQueueA dikaitkan dengan buffer log untuk pencatatan tunggu dan HWQueueB dikaitkan dengan buffer log untuk sinyal pengelogan.
- Ada objek pagar asli dengan mode pengguna D3DKMT_HANDLE FenceF.
- Tunggu GPU pada FenceF untuk Nilai V1 diantrekan ke HWQueueA pada saat CPUT1. Saat UMD membangun buffer perintah, UMD menyisipkan perintah yang menginstruksikan GPU untuk mencatat payload: LOG(FenceF, V1, DXGK_NATIVE_FENCE_LOG_OPERATION_WAIT_UNBLOCKED).
- Sinyal GPU ke FenceF dengan Nilai V1 diantrekan ke HWQueueB pada saat CPUT2. Saat UMD membangun buffer perintah, UMD menyisipkan perintah yang menginstruksikan GPU untuk mencatat payload: LOG(FenceF, V1, DXGK_NATIVE_FENCE_LOG_OPERATION_SIGNAL_EXECUTED).
Setelah penjadwal GPU menjalankan sinyal GPU pada HWQueueB pada waktu GPU GPUT1, penjadwal GPU membaca payload UMD dan mencatat peristiwa di log pagar yang disediakan OS untuk HWQueueB:
DXGK_NATIVE_FENCE_LOG_ENTRY LogEntry = {};
LogEntry.hNativeFence = FenceF;
LogEntry.FenceValue = V1;
LogEntry.OperationType = DXGK_NATIVE_FENCE_LOG_OPERATION_SIGNAL_EXECUTED;
LogEntry.FenceEndGpuTimestamp = GPUT1; // Time when UMD submits a command to the GPU
Setelah penjadwal GPU mengamati HWQueueA tidak diblokir pada waktu GPU GPUT2, penjadwal GPU membaca payload UMD dan mencatat peristiwa di log pagar yang disediakan OS untuk HWQueueA:
DXGK_NATIVE_FENCE_LOG_ENTRY LogEntry = {};
LogEntry.hNativeFence = FenceF;
LogEntry.FenceValue = V1;
LogEntry.OperationType = DXGK_NATIVE_FENCE_LOG_OPERATION_WAIT_UNBLOCKED;
LogEntry.FenceObservedGpuTimestamp = GPUTo; // Time that GPU acknowledged UMD's submitted command and queued the fence wait on HW
LogEntry.FenceEndGpuTimestamp = GPUT2;
Dxgkrnl dapat menghancurkan dan membuat ulang buffer log. Setiap kali melakukannya, ia memanggil DxgkDdiSetNativeFenceLogBuffer untuk menginformasikan KMD lokasi baru.
Tanda waktu CPU operasi antrean pagar
Ada sedikit manfaat untuk membuat log UMD tanda waktu CPU ini mengingat bahwa:
- Daftar perintah dapat direkam beberapa menit sebelum eksekusi GPU buffer perintah yang menyertakan daftar perintah.
- Beberapa menit ini bisa tidak berurutan dengan objek sinkronisasi lain yang berada dalam buffer perintah yang sama.
Ada biaya untuk menyertakan tanda waktu CPU dalam instruksi UMD ke buffer log yang ditulis GPU, sehingga tanda waktu CPU tidak termasuk dalam payload entri log.
Sebagai gantinya, runtime atau UMD dapat memancarkan peristiwa ETW yang diantrekan pagar asli dengan tanda waktu CPU pada saat daftar perintah sedang direkam. Alat dengan demikian dapat membangun garis waktu peristiwa yang diantrekan pagar dan selesai dengan menggabungkan tanda waktu CPU dari peristiwa baru ini dan tanda waktu GPU dari entri buffer log.
Urutan operasi pada GPU saat memberi sinyal atau membuka blokir pagar
UMD harus memastikan bahwa UMD mempertahankan urutan berikut saat membangun daftar perintah yang menginstruksikan GPU untuk memberi sinyal/membuka blokir pagar:
- Tulis nilai pagar baru untuk memagari GPU VA/CMP VA.
- Tulis payload log ke buffer log yang sesuai GPU VA/CMP VA.
- Naikkan pagar asli yang disinyalir mengganggu jika perlu.
Urutan operasi ini memastikan bahwa Dxgkrnl melihat entri log terbaru ketika interupsi dinaikkan ke OS.
Overrun buffer log diizinkan
GPU dapat menimpa buffer log dengan menimpa entri yang belum dilihat oleh OS. Ini melakukannya dengan menaikkan WraparoundCount.
Ketika OS akhirnya membaca log, OS dapat mendeteksi bahwa overrun terjadi dengan membandingkan nilai WraparoundCount baru di header log dengan nilai cache-nya. Jika terjadi overrun, OS memiliki opsi fallback berikut:
- Untuk membuka blokir pagar ketika terjadi overrun, OS memindai semua pagar dan menentukan pelayan mana yang tidak diblokir.
- Jika pelacakan diaktifkan, OS dapat memancarkan bendera dalam jejak untuk memberi tahu pengguna bahwa peristiwa hilang. Selain itu, ketika pelacakan diaktifkan, OS pertama-tama meningkatkan ukuran buffer log untuk mencegah overruns di tempat pertama.
UMD tidak perlu menerapkan dukungan tekanan balik saat mengembangkan entri buffer log.
Tanda waktu buffer log kosong atau berulang
Dalam kasus umum, Dxgkrnl mengharapkan bahwa tanda waktu dalam entri log meningkat secara monoton. Namun, ada skenario ketika tanda waktu entri log berikutnya nol atau sama dengan entri log sebelumnya.
Misalnya, dalam skenario dengan adaptor tampilan tertaut, salah satu adaptor berantai di LDA dapat melewati operasi penulisan pagar. Dalam hal ini, entri buffer log-nya memiliki tanda waktu nol. Dxgkrnl menangani kasus seperti itu. Yang mengatakan, Dxgkrnl tidak pernah mengharapkan tanda waktu entri log tertentu menjadi kurang dari entri log sebelumnya; yaitu, tanda waktu tidak pernah bisa mundur.
Memperbarui log pagar asli secara sinkron
Penulisan GPU untuk memperbarui nilai pagar dan buffer log yang sesuai harus memastikan bahwa penulisan sepenuhnya disebarluaskan sebelum CPU dibaca. Persyaratan ini mengharuskan penggunaan penghalang memori. Contohnya:
- Signal Fence(N): tulis N sebagai nilai baru saat ini
- Menulis entri LOG termasuk tanda waktu GPU
- MemoryBarrier
- Inkrement FirstFreeEntryIndex
- MemoryBarrier
- Gangguan pagar terpantau (N): baca Alamat "M" dan bandingkan nilai dengan N untuk memutuskan tentang memberikan gangguan CPU
Terlalu mahal untuk memasukkan dua hambatan pada setiap sinyal GPU, terutama ketika kemungkinan pemeriksaan gangguan bersyarat tidak terpenuhi dan tidak ada gangguan CPU yang diperlukan. Akibatnya, desain memindahkan biaya memasukkan salah satu penghalang memori dari GPU (produsen) ke CPU (konsumen). Dxgkrnl memanggil fungsi DxgkDdiUpdateNativeFenceLogs yang diperkenalkan untuk menyebabkan KMD secara sinkron membersihkan penulisan log pagar asli yang tertunda sesuai permintaan (mirip dengan bagaimana DxgkddiUpdateflipqueuelog diperkenalkan untuk flush log antrean flip HW).
Untuk operasi GPU:
- Signal Fence(N): tulis N sebagai nilai baru saat ini
- Tulis entri LOG termasuk tanda waktu GPU
- Inkrement FirstFreeEntryIndex
- MemoryBarrier => Memastikan FirstFreeEntryIndex sepenuhnya disebarluaskan
- Gangguan pagar yang dipantau (N): baca Alamat "M" dan bandingkan nilai dengan N untuk memutuskan tentang memberikan interupsi
Untuk operasi CPU:
Di pagar asli Dxgkrnl sinyal penghandel interupsi (DISPATCH_IRQL):
- Untuk setiap Log HWQueue: Baca FirstFreeEntryIndex dan tentukan apakah entri baru ditulis.
- Untuk setiap log HWQueue dengan entri baru: Panggil DxgkDdiUpdateNativeFenceLogs dan berikan handel kernel untuk HWQueues tersebut. Dalam DDI ini, KMD menyisipkan hambatan memori ke setiap HWQueue yang diberikan, yang memastikan bahwa semua penulisan entri log diterapkan.
- Dxgkrnl membaca entri log untuk mengekstrak payload tanda waktu.
Jadi, selama perangkat keras menyisipkan hambatan memori setelah menulis ke FirstFreeEntryIndex, Dxgkrnl selalu memanggil DDI KMD, memungkinkan KMD untuk menyisipkan hambatan memori sebelum Dxgkrnl membaca entri log apa pun.
Persyaratan perangkat keras di masa mendatang
Sebagian besar perangkat keras generasi saat ini mungkin hanya mendukung penulisan handel kernel objek pagar yang disinyalir di pagar asli yang disinyalir mengganggu. Desain ini dijelaskan sebelumnya di pagar asli yang memberi sinyal interupsi. Dalam hal ini, Dxgkrnl menangani payload interupsi, sebagai berikut:
- OS melakukan baca (berpotensi di seluruh PCI) dari nilai pagar.
- Mengetahui pagar mana yang diberi sinyal dan nilai pagar, OS membangkitkan pelayan CPU yang menunggu di pagar/nilai tersebut.
- Secara terpisah, untuk perangkat induk pagar ini, OS memindai buffer log dari semua HWQueues-nya. OS kemudian membaca entri buffer log tertulis terakhir untuk menentukan HWQueue mana yang melakukan sinyal dan mengekstrak payload tanda waktu yang sesuai. Pendekatan ini mungkin membaca beberapa nilai pagar secara berlebihan di seluruh PCI.
Pada platform masa depan, Dxgkrnl lebih suka mendapatkan array handel HwQueue kernel di pagar asli yang memberi sinyal interupsi. Pendekatan ini memungkinkan OS untuk:
- Baca entri buffer log terbaru untuk HwQueue tersebut. Perangkat pengguna tidak diketahui oleh handler interupsi; oleh karena itu, handel HwQueue ini perlu menjadi handel kernel.
- Pindai buffer log untuk entri log yang menunjukkan pagar mana yang telah disinyalir, dan ke nilai apa. Membaca hanya buffer log memastikan satu baca melalui PCI alih-alih harus membaca nilai pagar dan buffer log secara berlebihan. Pengoptimalan ini berhasil selama buffer log belum diserbu (menghilangkan entri yang tidak pernah dibaca Dxgkrnl ).
- Jika OS mendeteksi bahwa buffer log diserbu, ia kembali ke jalur yang tidak optimal yang membaca nilai langsung setiap pagar yang dimiliki oleh perangkat yang sama. Performa sebanding dengan jumlah pagar yang dimiliki oleh perangkat. Jika nilai pagar berada dalam memori video, maka bacaan ini koheren cache di seluruh PCI.
- Mengetahui pagar mana yang telah diberi sinyal dan nilai pagar, OS membangunkan pelayan CPU yang menunggu pagar/nilai tersebut.
Pengoptimalan pagar asli yang diinterupsi
Selain perubahan yang dijelaskan dalam Interupsi sinyal pagar asli, perubahan berikut juga dilakukan untuk mendukung pendekatan yang dioptimalkan:
- Batas OptimizedNativeFenceSignaledInterrupt ditambahkan ke DXGK_VIDSCHCAPS.
Jika didukung oleh perangkat keras, maka alih-alih mengisi array handel pagar yang mendapat sinyal, GPU hanya boleh menyebutkan handel KMD dari HWQueue yang berjalan ketika interupsi dinaikkan. Dxgkrnl memindai buffer log pagar untuk HWQueue ini dan membaca semua operasi pagar yang diselesaikan oleh GPU sejak pembaruan terakhir dan membuka blokir setiap pelayan CPU yang sesuai. Jika GPU tidak dapat menentukan subset pagar mana yang disinyalir, maka GPU harus menentukan handel NULL HWQueue. Ketika Dxgkrnl melihat handel NULL HWQueue, Dxgkrnl jatuh kembali untuk menyaring kembali buffer log dari semua HWQueues pada mesin ini untuk menentukan pagar mana yang mendapat sinyal.
Dukungan untuk pengoptimalan ini bersifat opsional; KMD harus mengatur batas DXGK_VIDSCHCAPS:OptimizedNativeFenceSignaledInterrupt jika didukung oleh perangkat keras. Jika batas OptimizedNativeFenceSignaledInterrupt tidak diatur, maka GPU/KMD harus mengikuti perilaku yang dijelaskan dalam Interupsi sinyal pagar asli.
Contoh interupsi sinyal pagar asli yang dioptimalkan
HWQueueA: Sinyal GPU ke Pagar F1, Nilai V1 -> Tulis ke entri buffer log E1 -> tidak diperlukan gangguan
HWQueueA: Sinyal GPU ke Pagar F1, Nilai V2 -> Tulis ke entri buffer log E2 -> tidak diperlukan gangguan
HWQueueA: Sinyal GPU ke Pagar F2, Nilai V3 -> Tulis ke entri buffer log E3 -> tidak diperlukan gangguan
HWQueueA: Sinyal GPU ke Pagar F2, Nilai V3 -> Tulis ke entri buffer log E4 -> interupsi dinaikkan
DXGKARGCB_NOTIFY_INTERRUPT_DATA FenceSignalISR = {}; FenceSignalISR.NodeOrdinal = 0; FenceSignalISR.EngineOrdinal = 0; FenceSignalISR.hHWQueue = A;Dxgkrnl membaca buffer log untuk HWQueueA. Ini membaca entri buffer log E1, E2, E3, dan E4 untuk mengamati pagar sinyal F1 @ Nilai V1, F1 @ Nilai V2, F2 @ Nilai V3, dan F2 @ Nilai V3, dan membuka blokir setiap pelayan yang menunggu pagar dan nilai tersebut
Pengelogan Opsional dan Wajib
Dukungan untuk pengelogan pagar asli untuk DXGK_NATIVE_FENCE_LOG_TYPE_WAITS dan DXGK_NATIVE_FENCE_LOG_TYPE_SIGNALS wajib dilakukan.
Di masa mendatang, jenis pengelogan lain mungkin ditambahkan hanya saat alat seperti GPUView mengaktifkan pengelogan ETW verbose di OS. OS harus menginformasikan UMD dan KMD tentang kapan pengelogan verbose diaktifkan dan dinonaktifkan sehingga pengelogan peristiwa verbose tersebut diaktifkan secara selektif.