Bagikan melalui


Peningkatan Direct3D 9Ex

Topik ini menjelaskan dukungan tambahan Windows 7 untuk Mode Balik Hadir dan statistik saat ini terkait di Direct3D 9Ex dan Desktop Window Manager. Aplikasi target mencakup aplikasi presentasi berbasis kecepatan video atau bingkai. Aplikasi yang menggunakan Mode Balik Direct3D 9Ex Hadir mengurangi beban sumber daya sistem saat DWM diaktifkan. Menyajikan peningkatan statistik yang terkait dengan Mode Flip Hadir memungkinkan aplikasi Direct3D 9Ex untuk mengontrol laju presentasi dengan lebih baik dengan memberikan umpan balik real-time dan mekanisme koreksi. Penjelasan terperinci dan penunjuk ke sumber daya sampel disertakan.

Topik ini berisi bagian berikut.

Apa yang Ditingkatkan tentang Direct3D 9Ex untuk Windows 7

Flip Mode Presentasi Direct3D 9Ex adalah mode yang ditingkatkan untuk menyajikan gambar di Direct3D 9Ex yang secara efisien menyerahkan gambar yang dirender ke Windows 7 Desktop Window Manager (DWM) untuk komposisi. Dimulai di Windows Vista, DWM menyusun seluruh Desktop. Ketika DWM diaktifkan, aplikasi mode berjendela menyajikan konten mereka di Desktop dengan menggunakan metode yang disebut Mode Blt Hadir ke DWM (atau Model Blt). Dengan Model Blt, DWM mempertahankan salinan permukaan Direct3D 9Ex yang dirender untuk komposisi Desktop. Ketika aplikasi diperbarui, konten baru disalin ke permukaan DWM melalui blt. Untuk aplikasi yang berisi konten Direct3D dan GDI, data GDI juga disalin ke permukaan DWM.

Tersedia di Windows 7, Flip Mode Present to DWM (atau Flip Model) adalah metode presentasi baru yang pada dasarnya memungkinkan passing handle permukaan aplikasi antara aplikasi mode berjendela dan DWM. Selain menyimpan sumber daya, Flip Model mendukung statistik saat ini yang ditingkatkan.

Statistik saat ini adalah informasi pengaturan waktu bingkai yang dapat digunakan aplikasi untuk menyinkronkan aliran video dan audio dan memulihkan dari gangguan pemutaran video. Informasi pengaturan waktu bingkai dalam statistik saat ini memungkinkan aplikasi untuk menyesuaikan tingkat presentasi bingkai video mereka untuk presentasi yang lebih lancar. Di Windows Vista, di mana DWM mempertahankan salinan permukaan bingkai yang sesuai untuk komposisi Desktop, aplikasi dapat menggunakan statistik saat ini yang disediakan oleh DWM. Metode untuk mendapatkan statistik saat ini masih akan tersedia di Windows 7 untuk aplikasi yang ada.

Di Windows 7, aplikasi berbasis Direct3D 9Ex yang mengadopsi Model Flip harus menggunakan API D3D9Ex untuk mendapatkan statistik saat ini. Ketika DWM diaktifkan, mode berjendela dan mode eksklusif layar penuh Aplikasi Direct3D 9Ex dapat mengharapkan informasi statistik saat ini yang sama saat menggunakan Model Balik. Direct3D 9Ex Flip Model menyajikan statistik memungkinkan aplikasi untuk mengkueri statistik saat ini secara real time, bukan setelah bingkai ditampilkan di layar; informasi statistik saat ini yang sama tersedia untuk aplikasi yang diaktifkan Flip-Model mode berjendela sebagai aplikasi layar penuh; bendera tambahan di API D3D9Ex memungkinkan aplikasi Flip Model untuk secara efektif membuang bingkai terlambat pada waktu presentasi.

Model Balik Direct3D 9Ex harus digunakan oleh aplikasi presentasi berbasis kecepatan video atau bingkai baru yang menargetkan Windows 7. Karena sinkronisasi antara DWM dan runtime Direct3D 9Ex, aplikasi yang menggunakan Model Balik harus menentukan antara 2 hingga 4 backbuffer untuk memastikan presentasi yang lancar. Aplikasi yang menggunakan informasi statistik saat ini akan mendapat manfaat dari penggunaan Model Flip yang diaktifkan penyempurnaan statistik saat ini.

Presentasi Mode Balik Direct3D 9EX

Peningkatan performa Direct3D 9Ex Flip Mode Present signifikan pada sistem ketika DWM aktif dan ketika aplikasi dalam mode berjendela, daripada dalam mode eksklusif layar penuh. Tabel dan ilustrasi berikut menunjukkan perbandingan penggunaan bandwidth memori yang disederhanakan dan pembacaan sistem dan penulisan aplikasi berjendela yang memilih Model Balik versus penggunaan default Model Blt.

Mode blt hadir untuk DWM Mode Balik D3D9Ex Hadir untuk DWM
1. Aplikasi memperbarui bingkainya (Tulis)
1. Aplikasi memperbarui bingkainya (Tulis)
2. Runtime Direct3D menyalin isi permukaan ke permukaan pengalihan DWM (Baca, Tulis)
2. Runtime Direct3D meneruskan permukaan aplikasi ke DWM
3. Setelah salinan permukaan bersama selesai, DWM merender permukaan aplikasi ke layar (Baca, Tulis)
3. DWM merender permukaan aplikasi ke layar (Baca, Tulis)

ilustrasi perbandingan model blt dan model flip

Mode Balik Hadir mengurangi penggunaan memori sistem dengan mengurangi jumlah bacaan dan tulis oleh runtime Direct3D untuk komposisi bingkai berjendela oleh DWM. Ini mengurangi konsumsi daya sistem dan penggunaan memori secara keseluruhan.

Aplikasi dapat memanfaatkan Direct3D 9Ex Flip Mode menghadirkan peningkatan statistik saat DWM aktif, terlepas dari apakah aplikasi dalam mode berjendela atau dalam mode eksklusif layar penuh.

Model pemrograman dan API

Aplikasi pengukur kecepatan video atau bingkai baru yang menggunakan DIRECT3D 9Ex API pada Windows 7 dapat memanfaatkan memori dan penghematan daya dan peningkatan presentasi yang ditawarkan oleh Mode Balik Hadir saat berjalan di Windows 7. (Saat berjalan pada versi Windows sebelumnya, runtime Direct3D default aplikasi ke Mode Blt Ada.)

Mode Balik Hadir mengharuskan aplikasi dapat memanfaatkan umpan balik statistik dan mekanisme koreksi saat DWM aktif secara real time. Namun, aplikasi yang menggunakan Mode Balik Hadir harus mengetahui batasan ketika mereka menggunakan rendering API GDI bersamaan.

Anda dapat memodifikasi aplikasi yang ada untuk memanfaatkan Flip Mode Present, dengan manfaat dan peringatan yang sama dengan aplikasi yang baru dikembangkan.

Cara Memilih Model Balik Direct3D 9Ex

Aplikasi Direct3D 9Ex yang menargetkan Windows 7 dapat memilih model Flip dengan membuat rantai pertukaran dengan nilai enumerasi D3DSWAPEFFECT_FLIPEX. Untuk memilih Model Balik, aplikasi menentukan struktur D3DPRESENT_PARAMETERS, lalu meneruskan penunjuk ke struktur ini saat mereka memanggil IDirect3D9Ex::CreateDeviceEx API. Bagian ini menjelaskan bagaimana aplikasi yang menargetkan Windows 7 menggunakan IDirect3D9Ex::CreateDeviceEx untuk memilih Model Balik. Untuk informasi selengkapnya tentang IDirect3D9Ex::CreateDeviceEx API, lihat IDirect3D9Ex::CreateDeviceEx di MSDN.

Untuk kenyamanan, sintaks D3DPRESENT_PARAMETERS dan IDirect3D9Ex::CreateDeviceEx diulang di sini.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);
typedef struct D3DPRESENT_PARAMETERS {
    UINT BackBufferWidth, BackBufferHeight;
    D3DFORMAT BackBufferFormat;
    UINT BackBufferCount;
    D3DMULTISAMPLE_TYPE MultiSampleType;
    DWORD MultiSampleQuality;
    D3DSWAPEFFECT SwapEffect;
    HWND hDeviceWindow;
    BOOL Windowed;
    BOOL EnableAutoDepthStencil;
    D3DFORMAT AutoDepthStencilFormat;
    DWORD Flags;
    UINT FullScreen_RefreshRateInHz;
    UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;

Saat Anda memodifikasi aplikasi Direct3D 9Ex untuk Windows 7 untuk memilih Model Balik, Anda harus mempertimbangkan item berikut tentang anggota D3DPRESENT_PARAMETERS yang ditentukan:

BackBufferCount

(Hanya Windows 7)

Ketika SwapEffect diatur ke jenis efek rantai pertukaran D3DSWAPEFFECT_FLIPEX baru, jumlah buffer belakang harus sama atau lebih besar dari 2, untuk mencegah penalti performa aplikasi sebagai akibat dari menunggu buffer Present sebelumnya yang akan dirilis oleh DWM.

Ketika aplikasi juga menggunakan statistik saat ini yang terkait dengan D3DSWAPEFFECT_FLIPEX, kami sarankan Anda mengatur jumlah buffer belakang ke dari 2 ke 4.

Menggunakan D3DSWAPEFFECT_FLIPEX pada Windows Vista atau versi sistem operasi sebelumnya akan kembali gagal dari CreateDeviceEx.

SwapEffect

(Hanya Windows 7)

Jenis efek rantai pertukaran D3DSWAPEFFECT_FLIPEX baru menunjuk saat aplikasi mengadopsi Mode Balik Hadir ke DWM. Ini memungkinkan aplikasi penggunaan memori dan daya yang lebih efisien, dan juga memungkinkan aplikasi untuk memanfaatkan statistik sajian layar penuh dalam mode berjendela. Perilaku aplikasi layar penuh tidak terpengaruh. Jika Windowed diatur ke TRUE dan SwapEffect diatur ke D3DSWAPEFFECT_FLIPEX, runtime membuat satu buffer back tambahan dan memutar handel mana pun milik buffer yang menjadi buffer depan pada waktu presentasi.

Bendera

(Hanya Windows 7)

Bendera D3DPRESENTFLAG_LOCKABLE_BACKBUFFER tidak dapat diatur jika SwapEffect diatur ke jenis efek rantai pertukaran D3DSWAPEFFECT_FLIPEX baru.

Panduan Desain untuk Aplikasi Model Balik Direct3D 9Ex

Gunakan panduan di bagian berikut untuk merancang aplikasi Model Direct3D 9Ex Flip Anda.

Gunakan Mode Balik yang Ada dalam HWND Terpisah dari Mode Blt Yang Ada

Aplikasi harus menggunakan Mode Balik Direct3D 9Ex Yang Ada dalam HWND yang tidak juga ditargetkan oleh API lain, termasuk Mode Blt Hadir Direct3D 9Ex, versi Direct3D lainnya, atau GDI. Mode Balik Ada dapat digunakan untuk menyajikan ke jendela anak; artinya, aplikasi dapat menggunakan Model Balik ketika tidak dicampur dengan Model Blt dalam HWND yang sama, seperti yang ditunjukkan dalam ilustrasi berikut.

ilustrasi jendela induk direct3d dan jendela anak gdi, masing-masing dengan hwnd sendiri

ilustrasi jendela induk gdi dan jendela turunan direct3d, masing-masing dengan hwnd sendiri

Karena Model Blt mempertahankan salinan tambahan permukaan, GDI dan konten Direct3D lainnya dapat ditambahkan ke HWND yang sama melalui pembaruan sepotong dari Direct3D dan GDI. Menggunakan Model Balik, hanya konten Direct3D 9Ex dalam D3DSWAPEFFECT_FLIPEX rantai pertukaran yang diteruskan ke DWM yang akan terlihat. Semua pembaruan konten Blt Model Direct3D atau GDI lainnya akan diabaikan, seperti yang ditunjukkan dalam ilustrasi berikut.

ilustrasi teks gdi yang mungkin tidak ditampilkan jika model flip digunakan dan konten direct3d dan gdi berada dalam hwnd yang sama

ilustrasi konten direct3d dan gdi di mana dwm diaktifkan dan aplikasi dalam mode berjendela

Oleh karena itu, Model Balik harus diaktifkan untuk buffer rantai pertukaran permukaan di mana Model Flip Direct3D 9Ex saja dirender ke seluruh HWND.

Jangan Gunakan Model Balik dengan ScrollWindow GDI atau ScrollWindowEx

Beberapa aplikasi Direct3D 9Ex menggunakan fungsi ScrollWindow atau ScrollWindowEx GDI untuk memperbarui konten jendela saat peristiwa gulir pengguna dipicu. ScrollWindow dan ScrollWindowEx melakukan blt konten jendela di layar saat jendela digulir. Fungsi-fungsi ini juga memerlukan pembaruan Model Blt untuk konten GDI dan Direct3D 9Ex. Aplikasi yang menggunakan salah satu fungsi tidak akan selalu menampilkan konten jendela yang terlihat yang bergulir di layar ketika aplikasi dalam mode berjendela dan DWM diaktifkan. Kami menyarankan agar Anda tidak menggunakan API ScrollWindow dan ScrollWindowEx GDI di aplikasi Anda, dan sebaliknya menggambar ulang kontennya di layar sebagai respons terhadap pengguliran.

Gunakan One D3DSWAPEFFECT_FLIPEX Swap Chain per HWND

Aplikasi yang menggunakan Model Balik tidak boleh menggunakan beberapa rantai pertukaran Model Balik yang menargetkan HWND yang sama.

Sinkronisasi Bingkai Aplikasi Model Balik Direct3D 9Ex

Statistik saat ini adalah informasi pengaturan waktu bingkai yang digunakan aplikasi media untuk menyinkronkan aliran video dan audio dan memulihkan dari gangguan pemutaran video. Untuk mengaktifkan ketersediaan statistik saat ini, aplikasi Direct3D 9Ex harus memastikan bahwa parameter BehaviorFlags yang diteruskan aplikasi ke IDirect3D9Ex::CreateDeviceEx berisi bendera perilaku perangkat D3DCREATE_ENABLE_PRESENTSTATS.

Untuk kenyamanan, sintaks IDirect3D9Ex::CreateDeviceEx diulang di sini.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);

Model Flip Direct3D 9Ex menambahkan bendera presentasi D3DPRESENT_FORCEIMMEDIATE yang memberlakukan perilaku bendera presentasi D3DPRESENT_INTERVAL_IMMEDIATE . Aplikasi Direct3D 9Ex menentukan bendera presentasi ini dalam parameter dwFlags yang diteruskan aplikasi ke IDirect3DDevice9Ex::P resentEx, seperti yang ditunjukkan di sini.

HRESULT PresentEx(
  CONST RECT *pSourceRect,
  CONST RECT *pDestRect,
  HWND hDestWindowOverride,
  CONST RGNDATA *pDirtyRegion,
  DWORD dwFlags
);

Saat mengubah aplikasi Direct3D 9Ex untuk Windows 7, Anda harus mempertimbangkan informasi berikut tentang bendera presentasi D3DPRESENT yang ditentukan:

D3DPRESENT_DONOTFLIP

Bendera ini hanya tersedia dalam mode layar penuh atau

(Hanya Windows 7)

ketika aplikasi mengatur anggota SwapEffect dari D3DPRESENT_PARAMETERS ke D3DSWAPEFFECT_FLIPEX dalam panggilan ke CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Hanya Windows 7)

Bendera ini hanya dapat ditentukan jika aplikasi mengatur anggota SwapEffect dari D3DPRESENT_PARAMETERS ke D3DSWAPEFFECT_FLIPEX dalam panggilan ke CreateDeviceEx. Aplikasi dapat menggunakan bendera ini untuk segera memperbarui permukaan dengan beberapa bingkai nanti dalam antrean DWM Present, pada dasarnya melompati bingkai perantara.

Aplikasi berkemampuan FlipEx berjendela dapat menggunakan bendera ini untuk segera memperbarui permukaan dengan bingkai yang nantinya berada dalam antrean DWM Present, melewati bingkai perantara. Ini sangat berguna untuk aplikasi media yang ingin membuang bingkai yang telah terdeteksi terlambat dan menyajikan bingkai berikutnya pada waktu komposisi. IDirect3DDevice9Ex::P resentEx mengembalikan kesalahan parameter yang tidak valid jika bendera ini ditentukan secara tidak benar.

Untuk mendapatkan informasi statistik saat ini, aplikasi mendapatkan struktur D3DPRESENTSTATS dengan memanggil API IDirect3DSwapChain9Ex::GetPresentStatistics.

Struktur D3DPRESENTSTATS berisi statistik tentang panggilan IDirect3DDevice9Ex::P resentEx. Perangkat harus dibuat dengan menggunakan panggilan IDirect3D9Ex::CreateDeviceEx dengan bendera D3DCREATE_ENABLE_PRESENTSTATS. Jika tidak, data yang dikembalikan oleh GetPresentStatistics tidak terdefinisi. Rantai pertukaran Direct3D 9Ex berkemampuan Flip-Model menyediakan informasi statistik yang ada dalam mode berjendela dan layar penuh.

Untuk rantai pertukaran Direct3D 9Ex berkemampuan Blt-Model dalam mode berjendela, semua nilai struktur D3DPRESENTSTATS akan menjadi nol.

Untuk statistik FlipEx saat ini, GetPresentStatistics mengembalikan D3DERR_PRESENT_STATISTICS_DISJOINT dalam situasi berikut:

  • Panggilan pertama ke GetPresentStatistics yang pernah ada, yang menunjukkan awal urutan
  • Transisi DWM dari aktif ke nonaktif
  • Perubahan mode: baik mode berjendela ke atau dari layar penuh atau layar penuh ke transisi layar penuh

Untuk kenyamanan, sintaks GetPresentStatistics diulang di sini.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

Metode IDirect3DSwapChain9Ex::GetLastPresentCount mengembalikan PresentCount terakhir, yaitu, ID Saat ini dari panggilan Present terakhir yang berhasil dibuat oleh perangkat tampilan yang terkait dengan rantai pertukaran. ID Saat Ini adalah nilai anggota PresentCount dari struktur D3DPRESENTSTATS . Untuk rantai pertukaran Direct3D 9Ex berkemampuan Blt-Model, sementara dalam mode berjendela, semua nilai struktur D3DPRESENTSTATS akan menjadi nol.

Untuk kenyamanan, sintaks IDirect3DSwapChain9Ex::GetLastPresentCount diulang di sini.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Saat Anda mengubah aplikasi Direct3D 9Ex untuk Windows 7, Anda harus mempertimbangkan informasi berikut tentang struktur D3DPRESENTSTATS:

  • Nilai PresentCount yang dikembalikan GetLastPresentCount tidak diperbarui saat panggilan PresentEx dengan D3DPRESENT_DONOTWAIT yang ditentukan dalam parameter dwFlags mengembalikan kegagalan.
  • Ketika PresentEx dipanggil dengan D3DPRESENT_DONOTFLIP, panggilan GetPresentStatistics berhasil tetapi tidak mengembalikan struktur D3DPRESENTSTATS yang diperbarui saat aplikasi dalam mode berjendela.
  • PresentRefreshCount versus SyncRefreshCount di D3DPRESENTSTATS:
    • PresentRefreshCount sama dengan SyncRefreshCount saat aplikasi hadir di setiap vsync.
    • SyncRefreshCount diperoleh pada interval vsync ketika saat ini dikirimkan, SyncQPCTime kira-kira waktu yang terkait dengan interval vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Sinkronisasi Bingkai untuk Aplikasi Berjendela Saat DWM Nonaktif

Ketika DWM nonaktif, aplikasi berjendela ditampilkan langsung ke layar monitor tanpa melalui rantai balik. Di Windows Vista, tidak ada dukungan untuk mendapatkan informasi statistik bingkai untuk aplikasi berjendela saat DWM nonaktif. Untuk mempertahankan API di mana aplikasi tidak perlu diketahui DWM, Windows 7 akan mengembalikan informasi statistik bingkai untuk aplikasi berjendela saat DWM nonaktif. Statistik bingkai dikembalikan ketika DWM nonaktif hanya estimasi.

Panduan Model Balik Direct3D 9Ex dan Sampel Statistik Saat Ini

Untuk memilih presentasi FlipEx untuk sampel Direct3D 9Ex

  1. Pastikan aplikasi sampel berjalan pada Windows 7 atau versi sistem operasi yang lebih baru.
  2. Atur anggota SwapEffect dari D3DPRESENT_PARAMETERS ke D3DSWAPEFFECT_FLIPEX dalam panggilan ke CreateDeviceEx.
    OSVERSIONINFO version;
    ZeroMemory(&version, sizeof(version));
    version.dwOSVersionInfoSize = sizeof(version);
    GetVersionEx(&version);
    
    // Sample would run only on Win7 or higher
    // Flip Model present and its associated present statistics behavior are only available on Windows 7 or higher operating system
    bool bIsWin7 = (version.dwMajorVersion > 6) || 
        ((version.dwMajorVersion == 6) && (version.dwMinorVersion >= 1));

    if (!bIsWin7)
    {
        MessageBox(NULL, L"This sample requires Windows 7 or higher", NULL, MB_OK);
        return 0;
    }

Untuk juga memilih FlipEx terkait Statistik Saat Ini untuk sampel Direct3D 9Ex

  • Atur D3DCREATE_ENABLE_PRESENTSTATS dalam parameter BehaviorFlags dari CreateDeviceEx.
    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));

    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_FLIPEX;        // Opts into Flip Model present for D3D9Ex swapchain
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = 256;                
    d3dpp.BackBufferHeight = 256;
    d3dpp.BackBufferCount = QUEUE_SIZE;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

    g_iWidth = d3dpp.BackBufferWidth;
    g_iHeight = d3dpp.BackBufferHeight;

    // Create the D3DDevice with present statistics enabled - set D3DCREATE_ENABLE_PRESENTSTATS for behaviorFlags parameter
    if(FAILED(g_pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_ENABLE_PRESENTSTATS,
                                      &d3dpp, NULL, &g_pd3dDevice)))
    {
        return E_FAIL;
    }

Untuk menghindari, mendeteksi, dan memulihkan dari gangguan

  1. Antrean Sajikan panggilan: jumlah backbuffer yang direkomendasikan adalah dari 2 hingga 4.

  2. Sampel Direct3D 9Ex menambahkan backbuffer implisit, panjang antrean Present yang sebenarnya adalah jumlah backbuffer + 1.

  3. Buat pembantu Sajikan struktur antrean untuk menyimpan semua ID Sajikan (PresentCount) yang berhasil dikirimkan dan PresentRefreshCount terkait, dihitung/diharapkan.

  4. Untuk mendeteksi kemunculan kesalahan:

    • Panggil GetPresentStatistics.
    • Dapatkan PRESENT ID (PresentCount) dan vsync count tempat bingkai ditampilkan (PresentRefreshCount) dari bingkai yang statistik saat ini diperoleh.
    • Ambil PresentRefreshCount yang diharapkan (TargetRefresh dalam kode sampel) yang terkait dengan ID Sajikan.
    • Jika PresentRefreshCount aktual lebih lambat dari yang diharapkan, kesalahan telah terjadi.
  5. Untuk memulihkan dari kesalahan:

    • Hitung berapa banyak bingkai yang akan dilewati (g_ variabel iImmediates dalam kode sampel).
    • Sajikan bingkai yang dilewati dengan interval D3DPRESENT_FORCEIMMEDIATE.

Pertimbangan untuk deteksi dan pemulihan kesalahan

  1. Pemulihan glitch mengambil variabel N (g_iQueueDelay dalam kode sampel) panggilan Sajikan di mana N (g_iQueueDelay) sama dengan g_iImmediates ditambah panjang antrean Sekarang, yaitu:

    • Melompati bingkai dengan interval Sajikan D3DPRESENT_FORCEIMMEDIATE, plus
    • Hadiah Antrean yang perlu diproses
  2. Atur batas ke panjang glitch (GLITCH_RECOVERY_LIMIT dalam sampel). Jika aplikasi sampel tidak dapat pulih dari kesalahan yang terlalu panjang (misalnya, 1 detik, atau 60 vsyncs pada monitor 60Hz), lompat ke animasi terputus-putus dan atur ulang antrean Pembantu Sajikan.

VOID Render()
{
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    g_pd3dDevice->BeginScene();

    // Compute new animation parameters for time and frame based animations

    // Time-based is a difference between base and current SyncRefreshCount
    g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
    // Frame-based is incrementing frame value
    g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;

    RenderBlurredMesh(TRUE);    // Time-based
    RenderBlurredMesh(FALSE);   // Frame-based

    g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;

    DrawText();

    g_pd3dDevice->EndScene();

    // Performs glitch recovery if glitch was detected
    if (g_bGlitchRecovery && (g_iImmediates > 0))
    {
        // If we have present immediates queued as a result of glitch detected, issue forceimmediate Presents for glitch recovery 
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE);
        g_iImmediates--;
        g_iShowingGlitchRecovery = MESSAGE_SHOW;
    }
    // Otherwise, Present normally
    else
    {
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, 0);
    }

    // Add to helper Present queue: PresentID + expected present refresh count of last submitted Present
    UINT PresentCount;
    g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
    g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);
    
    // QueueDelay specifies # Present calls to be processed before another glitch recovery attempt
    if (g_iQueueDelay > 0)
    {
        g_iQueueDelay--;
    }

    if (g_bGlitchRecovery)
    {
        // Additional DONOTFLIP presents for frame conversions, which basically follows the same logic, but without rendering
        for (DWORD i = 0; i < g_iDoNotFlipNum; i++)
        {
            if (g_TargetRefreshCount != -1)
            {
                g_TargetRefreshCount++;
                g_iFrameNumber++;
                g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
                g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;
                g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;
            }
            
            if (g_iImmediates > 0)
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE | D3DPRESENT_DONOTFLIP);
                g_iImmediates--;
            }
            else
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTFLIP);
            }
            UINT PresentCount;
            g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
            g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);

            if (g_iQueueDelay > 0)
            {
                g_iQueueDelay--;
            }
        }
    }

    // Check Present Stats info for glitch detection 
    D3DPRESENTSTATS PresentStats;

    // Obtain present statistics information for successfully displayed presents
    HRESULT hr = g_pd3dSwapChain->GetPresentStats(&PresentStats);

    if (SUCCEEDED(hr))
    {
        // Time-based update
        g_LastSyncRefreshCount = PresentStats.SyncRefreshCount;
        if ((g_SyncRefreshCount == -1) && (PresentStats.PresentCount != 0))
        {
            // First time SyncRefreshCount is reported, use it as base
            g_SyncRefreshCount = PresentStats.SyncRefreshCount;
        }

        // Fetch frame from the queue...
        UINT TargetRefresh = g_Queue.DequeueFrame(PresentStats.PresentCount);

        // If PresentStats returned a really old frame that we no longer have in the queue, just don't do any glitch detection
        if (TargetRefresh == FRAME_NOT_FOUND)
            return;

        if (g_TargetRefreshCount == -1)
        {
            // This is first time issued frame is confirmed by present stats, so fill target refresh count for all frames in the queue
            g_TargetRefreshCount = g_Queue.FillRefreshCounts(PresentStats.PresentCount, g_SyncRefreshCount);
        } 
        else
        {
            g_TargetRefreshCount++;
            g_iFrameNumber++;

            // To determine whether we're glitching, see if our estimated refresh count is confirmed
            // if the frame is displayed later than the expected vsync count
            if (TargetRefresh < PresentStats.PresentRefreshCount)
            {
                // then, glitch is detected!

                // If glitch is too big, don't bother recovering from it, just jump animation
                if ((PresentStats.PresentRefreshCount - TargetRefresh) > GLITCH_RECOVERY_LIMIT)
                {
                    g_iStartFrame += PresentStats.SyncRefreshCount - g_SyncRefreshCount;
                    ResetAnimation();
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;    
                } 
                // Otherwise, compute number of immediate presents to recover from it -- if we?re not still trying to recover from another glitch
                else if (g_iQueueDelay == 0)
                {
                      // skip frames to catch up to expected refresh count
                    g_iImmediates = PresentStats.PresentRefreshCount - TargetRefresh;
                    // QueueDelay specifies # Present calls before another glitch recovery 
                    g_iQueueDelay = g_iImmediates + QUEUE_SIZE;
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;
                }
            }
            else
            {
                // No glitch, reset glitch count
                g_iGlitchesInaRow = 0;
            }
        }
    }
    else if (hr == D3DERR_PRESENT_STATISTICS_DISJOINT)
    {
        // D3DERR_PRESENT_STATISTICS_DISJOINT means measurements should be started from the scratch (could be caused by mode change or DWM on/off transition)
        ResetAnimation();
    }

    // If we got too many glitches in a row, reduce framerate conversion factor (that is, render less frames)
    if (g_iGlitchesInaRow == FRAMECONVERSION_GLITCH_LIMIT)
    {
        if (g_iDoNotFlipNum < FRAMECONVERSION_LIMIT)
        {
            g_iDoNotFlipNum++;
        }
        g_iGlitchesInaRow = 0;
        g_iShowingDoNotFlipBump = MESSAGE_SHOW;
    }
}

Contoh skenario

  • Ilustrasi berikut menunjukkan aplikasi dengan jumlah backbuffer 4. Oleh karena itu, panjang antrean Sajikan yang sebenarnya adalah 5.

    ilustrasi bingkai yang dirender applicas dan antrean sajikan

    Bingkai A ditargetkan untuk masuk ke layar pada jumlah interval sinkronisasi 1 tetapi terdeteksi bahwa itu ditampilkan pada jumlah interval sinkronisasi 4. Oleh karena itu kesalahan telah terjadi. 3 bingkai berikutnya disajikan dengan D3DPRESENT_INTERVAL_FORCEIMMEDIATE. Kesalahan harus mengambil total 8 Panggilan saat ini sebelum dipulihkan - bingkai berikutnya akan ditampilkan sesuai jumlah interval sinkronisasi yang ditargetkan.

Ringkasan Rekomendasi Pemrograman untuk Sinkronisasi Bingkai

  • Buat daftar cadangan semua ID LastPresentCount (diperoleh melalui GetLastPresentCount) dan perkiraan terkait PresentRefreshCount dari semua Presents yang dikirimkan.

    Catatan

    Ketika aplikasi memanggil PresentEx dengan D3DPRESENT_DONOTFLIP, panggilan GetPresentStatistics berhasil tetapi tidak mengembalikan struktur D3DPRESENTSTATS yang diperbarui ketika aplikasi dalam mode berjendela.

  • Panggil GetPresentStatistics untuk mendapatkan PresentRefreshCount aktual yang terkait dengan setiap ID Sajian bingkai yang ditampilkan, untuk memastikan bahwa aplikasi menangani pengembalian kegagalan dari panggilan.

  • Jika PresentRefreshCount aktual lebih lambat dari perkiraan PresentRefreshCount, kesalahan terdeteksi. Kompensasi dengan mengirimkan bingkai tertinggal yang Ada dengan D3DPRESENT_FORCEIMMEDIATE.

  • Ketika satu bingkai disajikan terlambat dalam antrean Sekarang, semua bingkai antrean berikutnya akan disajikan terlambat. D3DPRESENT_FORCEIMMEDIATE hanya akan mengoreksi bingkai berikutnya yang akan disajikan setelah semua bingkai antrean. Oleh karena itu, jumlah Antrean saat ini atau backbuffer tidak boleh terlalu panjang -- sehingga ada lebih sedikit gangguan bingkai untuk mengejar ketinggalan. Jumlah backbuffer optimal adalah 2 hingga 4.

  • Jika perkiraan PresentRefreshCount lebih lambat dari PresentRefreshCount aktual, pembatasan DWM mungkin telah terjadi. Solusi berikut dimungkinkan:

    • mengurangi panjang antrean Saat ini
    • mengurangi persyaratan memori GPU dengan cara lain selain mengurangi panjang Antrean Saat Ini (yaitu, mengurangi kualitas, menghapus efek, dan sebagainya)
    • menentukan DwmEnableMMCSS untuk mencegah pembatasan DWM secara umum
  • Verifikasi fungsionalitas tampilan aplikasi dan performa statistik bingkai dalam skenario berikut:

    • dengan DWM aktif dan nonaktif
    • mode eksklusif layar penuh dan berjendela
    • perangkat keras kemampuan yang lebih rendah
  • Ketika aplikasi tidak dapat pulih dari sejumlah besar bingkai yang salah dengan D3DPRESENT_FORCEIMMEDIATE Ada, aplikasi tersebut berpotensi melakukan operasi berikut:

    • kurangi penggunaan CPU dan GPU dengan merender dengan beban kerja yang lebih sedikit.
    • dalam kasus dekode video, dekode lebih cepat dengan mengurangi kualitas dan, oleh karena itu, penggunaan CPU dan GPU.

Kesimpulan tentang Direct3D 9Ex Improvements

Pada Windows 7, aplikasi yang menampilkan kecepatan bingkai video atau pengukur selama presentasi dapat memilih Model Balik. Peningkatan statistik saat ini yang terkait dengan Flip Model Direct3D 9Ex dapat menguntungkan aplikasi yang menyinkronkan presentasi per kecepatan bingkai, dengan umpan balik real time untuk deteksi dan pemulihan kesalahan. Pengembang yang mengadopsi Model Flip Direct3D 9Ex harus mempertimbangkan penargetan HWND terpisah dari konten GDI dan sinkronisasi kecepatan bingkai. Lihat detail dalam topik ini. Untuk dokumentasi tambahan, lihat Pusat Pengembang DirectX di MSDN.

Ajakan ke Tindakan

Kami mendorong Anda untuk menggunakan Direct3D 9Ex Flip Model dan statistiknya saat ini pada Windows 7 ketika Anda membuat aplikasi yang mencoba menyinkronkan kecepatan bingkai presentasi atau memulihkan dari gangguan tampilan.

Pusat Pengembang DirectX di MSDN