Bagikan melalui


Berbagi permukaan antara API grafis Windows

Topik ini memberikan gambaran umum teknis interoperabilitas menggunakan berbagi permukaan antara API grafis Windows, termasuk Direct3D 11, Direct2D, DirectWrite, Direct3D 10, dan Direct3D 9Ex. Jika Anda sudah memiliki pengetahuan kerja tentang API ini, makalah ini dapat membantu Anda menggunakan beberapa API untuk merender ke permukaan yang sama dalam aplikasi yang dirancang untuk sistem operasi Windows 7 atau Windows Vista. Topik ini juga menyediakan panduan praktik terbaik dan penunjuk ke sumber daya tambahan.

Catatan

Untuk interoperabilitas Direct2D dan DirectWrite pada runtime DirectX 11.1, Anda dapat menggunakan perangkat Direct2D dan konteks perangkat untuk dirender langsung ke perangkat Direct3D 11.

 

Topik ini berisi bagian berikut.

Pengantar

Dalam dokumen ini, interoperabilitas API grafis Windows mengacu pada berbagi permukaan penyajian yang sama oleh API yang berbeda. Interoperabilitas semacam ini memungkinkan aplikasi untuk membuat tampilan yang menarik dengan memanfaatkan beberapa API grafis Windows, dan untuk memudahkan migrasi ke teknologi baru dengan mempertahankan kompatibilitas dengan API yang ada.

Di Windows 7 (dan Windows Vista SP2 dengan Windows 7 Interop Pack, Vista 7IP), API rendering grafis adalah Direct3D 11, Direct2D, Direct3D 10.1, Direct3D 10.0, Direct3D 9Ex, Direct3D 9c dan API Direct3D sebelumnya, serta GDI dan GDI+. Komponen Pencitraan Windows (WIC) dan DirectWrite adalah teknologi terkait untuk pemrosesan gambar, dan Direct2D melakukan penyajian teks. DirectX Video Acceleration API (DXVA), berdasarkan Direct3D 9c dan Direct3D 9Ex, digunakan untuk pemrosesan video.

Seiring berkembangnya API grafis Windows menjadi berbasis Direct3D, Microsoft menginvestasikan lebih banyak upaya dalam memastikan interoperabilitas di seluruh API. API Direct3D yang baru dikembangkan dan API tingkat yang lebih tinggi berdasarkan API Direct3D juga memberikan dukungan jika diperlukan untuk menjegal kompatibilitas dengan API yang lebih lama. Untuk menggambarkan, aplikasi Direct2D dapat menggunakan Direct3D 10.1 dengan berbagi perangkat Direct3D 10.1. Selain itu, API Direct3D 11, Direct2D, dan Direct3D 10.1 semuanya dapat memanfaatkan DirectX Graphics Infrastructure (DXGI) 1.1, yang memungkinkan permukaan bersama yang disinkronkan yang sepenuhnya mendukung interoperabilitas di antara API ini. API berbasis DXGI 1.1 beroperasi dengan GDI, dan dengan GDI+ berdasarkan asosiasi, dengan mendapatkan konteks perangkat GDI dari permukaan DXGI 1.1. Untuk informasi selengkapnya, lihat dokumentasi interoperabilitas DXGI dan GDI yang tersedia di MSDN.

Berbagi permukaan yang tidak disinkronkan didukung oleh runtime Direct3D 9Ex. Aplikasi video berbasis DXVA dapat menggunakan pembantu interoperabilitas Direct3D 9Ex dan DXGI untuk interoperabilitas DXVA berbasis Direct3D 9Ex dengan Direct3D 11 untuk shader komputasi, atau dapat beroperasi dengan Direct2D untuk kontrol 2D atau penyajian teks. WIC dan DirectWrite juga beroperasi dengan GDI, Direct2D, dan oleh asosiasi, API Direct3D lainnya.

Runtime Direct3D 10.0, Direct3D 9c, dan Direct3D yang lebih lama tidak mendukung permukaan bersama. Salinan memori sistem akan terus digunakan untuk interoperabilitas dengan API berbasis GDI atau DXGI.

Perhatikan bahwa skenario interoperabilitas dalam dokumen ini mengacu pada beberapa API grafis yang dirender ke permukaan penyajian bersama, bukan ke jendela aplikasi yang sama. Sinkronisasi untuk API terpisah yang menargetkan permukaan berbeda yang kemudian disusun ke jendela yang sama berada di luar cakupan makalah ini.

Gambaran Umum Interoperabilitas API

Interoperabilitas berbagi permukaan API grafis Windows dapat dijelaskan dalam hal skenario API-ke-API dan fungsionalitas interoperabilitas yang sesuai. Pada Windows 7 dan dimulai dengan Windows Vista SP2 dengan 7IP, API baru dan runtime terkait mencakup Direct2D dan teknologi terkait: Direct3D 11 dan DXGI 1.1. Performa GDI juga ditingkatkan di Windows 7. Direct3D 10.1 diperkenalkan di Windows Vista SP1. Diagram berikut menunjukkan dukungan interoperabilitas antara API.

diagram dukungan interoperabilitas antara api grafis windows

Dalam diagram ini, panah menunjukkan skenario interoperabilitas di mana permukaan yang sama dapat diakses oleh API yang terhubung. Panah biru menunjukkan mekanisme interoperabilitas yang diperkenalkan di Windows Vista. Panah hijau menunjukkan dukungan interoperabilitas untuk API atau peningkatan baru yang membantu API yang lebih lama beroperasi dengan API yang lebih baru. Misalnya, panah hijau mewakili berbagi perangkat, dukungan permukaan bersama yang disinkronkan, pembantu sinkronisasi Direct3D 9Ex/DXGI, dan mendapatkan konteks perangkat GDI dari permukaan yang kompatibel.

Skenario Interoperabilitas

Pada Windows 7 dan Windows Vista 7IP, penawaran utama dari API grafis Windows mendukung beberapa RENDER API ke permukaan DXGI 1.1 yang sama.

Direct3D 11, Direct3D 10.1, Direct2D — Interoperabilitas satu sama lain

API Direct3D 11, Direct3D 10.1 dan Direct2D (dan API terkait seperti DirectWrite dan WIC) dapat saling beroperasi menggunakan berbagi perangkat Direct3D 10.1 atau permukaan bersama yang disinkronkan.

Direct3D 10.1 Berbagi Perangkat dengan Direct2D

Berbagi perangkat antara Direct2D dan Direct3D 10.1 memungkinkan aplikasi untuk menggunakan kedua API untuk secara mulus dan efisien dirender ke permukaan DXGI 1.1 yang sama, menggunakan objek perangkat Direct3D yang mendasar yang sama. Direct2D menyediakan kemampuan untuk memanggil API Direct2D menggunakan perangkat Direct3D 10.1 yang ada, memanfaatkan fakta bahwa Direct2D dibangun di atas runtime Direct3D 10.1 dan DXGI 1.1. Cuplikan kode berikut menggambarkan bagaimana Direct2D mendapatkan target render perangkat Direct3D 10.1 dari permukaan DXGI 1.1 yang terkait dengan perangkat. Target render perangkat Direct3D 10.1 dapat menjalankan panggilan gambar Direct2D antara BEGINDraw dan ENDDraw API.

// Direct3D 10.1 Device and Swapchain creation
HRESULT hr = D3D10CreateDeviceandSwapChain1(
                pAdapter,
                DriverType,
                Software,
                D3D10_CREATE_DEVICE_BGRA_SUPPORT,
                featureLevel,
                D3D10_1_SDK_VERSION,
                pSwapChainDesc,
                &pSwapChain,
                &pDevice
                );

hr = pSwapChain->GetBuffer(
        0,
        __uuidof(IDXGISurface),
        (void **)&pDXGIBackBuffer
        ));

// Direct3D 10.1 API rendering calls
...

hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &m_spD2DFactory
        ));

pD2DFactory->CreateDxgiSurfaceRenderTarget(
        pDXGIBackBuffer,
        &renderTargetProperties,
        &pD2DBackBufferRenderTarget
        ));
...

pD2DBackBufferRenderTarget->BeginDraw();
//Direct2D API rendering calls
...

pD2DBackBufferRenderTarget->EndDraw();

pSwapChain->Present(0, 0);

Keterangan

  • Perangkat Direct3D 10.1 terkait harus mendukung format BGRA. Perangkat tersebut dibuat dengan memanggil D3D10CreateDevice1 dengan parameter D3D10_CREATE_DEVICE_BGRA_SUPPORT. Format BGRA didukung dimulai dengan direct3D 10 feature level 9.1.
  • Aplikasi tidak boleh membuat beberapa ID2D1RenderTargets yang mengaitkan ke perangkat Direct3D10.1 yang sama.
  • Untuk performa optimal, simpan setidaknya satu sumber daya setiap saat, seperti tekstur atau permukaan yang terkait dengan perangkat.

Berbagi perangkat cocok untuk penggunaan satu rangkaian tunggal dalam proses dari satu perangkat penyajian yang dibagikan oleh API penyajian Direct3D 10.1 dan Direct2D. Permukaan bersama yang disinkronkan memungkinkan penggunaan multi-utas, dalam proses, dan di luar proses dari beberapa perangkat penyajian yang digunakan oleh API Direct3D 10.1, Direct2D, dan Direct3D 11.

Metode lain dari interoperabilitas Direct3D 10.1 dan Direct2D adalah dengan menggunakan ID3D1RenderTarget::CreateSharedBitmap, yang membuat objek ID2D1Bitmap dari IDXGISurface. Anda dapat menulis adegan Direct3D10.1 ke bitmap dan merendernya dengan Direct2D. Untuk informasi selengkapnya, lihat Metode ID2D1RenderTarget::CreateSharedBitmap.

Rasterisasi Perangkat Lunak Direct2D

Berbagi perangkat dengan Direct3D 10.1 tidak didukung saat menggunakan perender perangkat lunak Direct2D, misalnya, dengan menentukan D2D1_RENDER_TARGET_USAGE_FORCE_SOFTWARE_RENDERING di D2D1_RENDER_TARGET_USAGE saat membuat target render Direct2D.

Direct2D dapat menggunakan rasterizer perangkat lunak WARP10 untuk berbagi perangkat dengan Direct3D 10 atau Direct3D 11, tetapi performanya menurun secara signifikan.

DXGI 1.1 Permukaan Bersama yang Disinkronkan

Direct3D 11, Direct3D 10.1 dan Direct2D API semuanya menggunakan DXGI 1.1, yang menyediakan fungsionalitas untuk menyinkronkan membaca dari dan menulis ke permukaan memori video yang sama (DXGISurface1) oleh dua perangkat Direct3D atau lebih. Perangkat penyajian menggunakan permukaan bersama yang disinkronkan dapat berupa perangkat Direct3D 10.1 atau Direct3D 11, masing-masing berjalan dalam proses atau lintas proses yang sama.

Aplikasi dapat menggunakan permukaan bersama yang disinkronkan untuk beroperasi antara perangkat berbasis DXGI 1.1, seperti Direct3D 11 dan Direct3D 10.1, atau antara Direct3D 11 dan Direct2D, dengan mendapatkan perangkat Direct3D 10.1 dari objek target render Direct2D.

Di DIRECT3D 10.1 dan API yang lebih baru, untuk menggunakan DXGI 1.1, pastikan bahwa perangkat Direct3D dibuat menggunakan objek adaptor DXGI 1.1, yang dijumlahkan dari objek pabrik DXGI 1.1. Panggil CreateDXGIFactory1 untuk membuat objek IDXGIFactory1, dan EnumAdapters1 untuk menghitung objek IDXGIAdapter1. Objek IDXGIAdapter1 perlu diteruskan sebagai bagian dari panggilan D3D10CreateDevice atau D3D10CreateDeviceAndSwapChain. Untuk informasi lebih lanjut tentang API DXGI 1.1, silakan lihat Panduan Pemrograman untuk DXGI.

API

D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX
Saat membuat sumber daya bersama yang disinkronkan, atur D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX di D3D10_RESOURCE_MISC_FLAG.

typedef enum D3D10_RESOURCE_MISC_FLAG {
    D3D10_RESOURCE_MISC_GENERATE_MIPS      = 0x1L,
    D3D10_RESOURCE_MISC_SHARED             = 0x2L,
    D3D10_RESOURCE_MISC_TEXTURECUBE        = 0x4L,
    D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX  = 0x10L,
    D3D10_RESOURCE_MISC_GDI_COMPATIBLE     = 0x20L,
}   D3D10_RESOURCE_MISC_FLAG;

D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX
Memungkinkan sumber daya yang dibuat untuk disinkronkan menggunakan API IDXGIKeyedMutex::AcquireSync dan ReleaseSync. Pembuatan sumber daya berikut API Direct3D 10.1 yang semuanya mengambil parameter D3D10_RESOURCE_MISC_FLAG telah diperluas untuk mendukung bendera baru.

  • ID3D10Device1::CreateTexture1D
  • ID3D10Device1::CreateTexture2D
  • ID3D10Device1::CreateTexture3D
  • ID3D10Device1::CreateBuffer

Jika salah satu fungsi yang tercantum dipanggil dengan set bendera D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX, antarmuka yang dikembalikan dapat dikueri untuk antarmuka IDXGIKeyedMutex, yang mengimplementasikan ACQUIRESync dan ReleaseSync API untuk menyinkronkan akses ke permukaan. Perangkat yang membuat permukaan dan perangkat lain yang membuka permukaan (menggunakan OpenSharedResource) diperlukan untuk memanggil IDXGIKeyedMutex::AcquireSync sebelum perintah penyajian ke permukaan, dan IDXGIKeyedMutex::ReleaseSync ketika selesai dirender.
Perangkat WARP dan REF tidak mendukung sumber daya bersama. Mencoba membuat sumber daya dengan bendera ini pada perangkat WARP atau REF akan menyebabkan metode buat mengembalikan kode kesalahan E_OUTOFMEMORY.
ANTARMUKA IDXGIKEYEDMUTEX
Antarmuka baru di DXGI 1.1, IDXGIKeyedMutex, mewakili mutex bertanda kunci, yang memungkinkan akses eksklusif ke sumber daya bersama yang digunakan oleh beberapa perangkat. Untuk dokumentasi referensi tentang antarmuka ini dan dua metodenya, AcquireSync dan ReleaseSync, lihat IDXGIKeyedMutex.

Sampel: Berbagi Permukaan yang Disinkronkan Antara dua Perangkat Direct3D 10.1

Contoh di bawah ini menggambarkan berbagi permukaan antara dua perangkat Direct3D 10.1. Permukaan bersama yang disinkronkan dibuat oleh perangkat Direct3D10.1.

// Create Sync Shared Surface using Direct3D10.1 Device 1.
D3D10_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
// must match swapchain format in order to CopySubresourceRegion.
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
// creates 2D texture as a Synchronized Shared Surface.
desc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
ID3D10Texture2D* g_pShared = NULL;
g_pd3dDevice1->CreateTexture2D( &desc, NULL, &g_pShared );

// QI IDXGIResource interface to synchronized shared surface.
IDXGIResource* pDXGIResource = NULL;
g_pShared->QueryInterface(__uuidof(IDXGIResource), (LPVOID*) &pDXGIResource);

// obtain handle to IDXGIResource object.
pDXGIResource->GetSharedHandle(&g_hsharedHandle);
pDXGIResource->Release();
if ( !g_hsharedHandle )
    return E_FAIL;

// QI IDXGIKeyedMutex interface of synchronized shared surface's resource handle.
hr = g_pShared->QueryInterface( __uuidof(IDXGIKeyedMutex),
    (LPVOID*)&g_pDXGIKeyedMutex_dev1 );
If ( FAILED( hr ) || ( g_pDXGIKeyedMutex_dev1 == NULL ) )
    return E_FAIL;

Perangkat Direct3D10.1 yang sama dapat memperoleh permukaan bersama yang disinkronkan untuk penyajian dengan memanggil AcquireSync, lalu melepaskan permukaan untuk penyajian perangkat lain dengan memanggil ReleaseSync. Ketika tidak berbagi permukaan bersama yang disinkronkan dengan perangkat Direct3D lainnya, pembuat dapat memperoleh dan merilis permukaan bersama yang disinkronkan (untuk memulai dan mengakhiri penyajian) dengan memperoleh dan melepaskan menggunakan nilai kunci yang sama.

// Obtain handle to Sync Shared Surface created by Direct3D10.1 Device 1.
hr = g_pd3dDevice2->OpenSharedResource( g_hsharedHandle,__uuidof(ID3D10Texture2D),
                                        (LPVOID*) &g_pdev2Shared);
if (FAILED (hr))
    return hr;
hr = g_pdev2Shared->QueryInterface( __uuidof(IDXGIKeyedMutex),
                                    (LPVOID*) &g_pDXGIKeyedMutex_dev2);
if( FAILED( hr ) || ( g_pDXGIKeyedMutex_dev2 == NULL ) )
    return E_FAIL;

// Rendering onto Sync Shared Surface from D3D10.1 Device 1 using D3D10.1 Device 2.
UINT acqKey = 1;
UINT relKey = 0;
DWORD timeOut = 5;
DWORD result = g_pDXGIKeyedMutex_dev2->AcquireSync(acqKey, timeOut);
if ( result == WAIT_OBJECT_0 )
    // Rendering calls using Device 2.
else
    // Handle unable to acquire shared surface error.
result = g_pDXGIKeyedMutex_dev2->ReleaseSync(relKey));
if (result == WAIT_OBJECT_0)
    return S_OK;

Perangkat Direct3D10.1 kedua dapat memperoleh permukaan bersama yang disinkronkan untuk penyajian dengan memanggil AcquireSync, lalu merilis permukaan untuk penyajian perangkat pertama dengan memanggil ReleaseSync. Perhatikan bahwa perangkat 2 dapat memperoleh permukaan bersama yang disinkronkan menggunakan nilai kunci yang sama dengan yang ditentukan dalam panggilan ReleaseSync oleh perangkat 1.

// Rendering onto Sync Shared Surface from D3D10.1 Device 1 using D3D10.1 Device 1.
UINT acqKey = 0;
UINT relKey = 1;
DWORD timeOut = 5;
DWORD result = g_pDXGIKeyedMutex_dev1->AcquireSync(acqKey, timeOut);
if (result == WAIT_OBJECT_0)
    // Rendering calls using Device 1.
else
    // Handle unable to acquire shared surface error.
result = g_pDXGIKeyedMutex_dev1->ReleaseSync(relKey));
if ( result == WAIT_OBJECT_0 )
    return S_OK;

Perangkat tambahan yang berbagi permukaan yang sama dapat bergiliran memperoleh dan melepaskan permukaan dengan menggunakan kunci tambahan, seperti yang ditunjukkan dalam panggilan berikut.

// Within Device 1's process/thread:
// Rendering onto Sync Shared Surface from D3D10.1 Device 1 using D3D10.1 Device 1
result = g_pDXGIKeyedMutex_dev1->AcquireSync(0, timeOut);
// Rendering calls using Device 1
...
result = g_pDXGIKeyedMutex_dev1->ReleaseSync(1);
...
////////////////////////////////////////////////////////////////////////////
// Within Device 2's process/thread:
// Rendering onto Sync Shared Surface from D3D10.1 Device 1 using D3D10.1 Device 2
result = g_pDXGIKeyedMutex_dev2->AcquireSync(1, timeOut);
// Rendering calls using Device 2
...
result = g_pDXGIKeyedMutex_dev1->ReleaseSync(2);

////////////////////////////////////////////////////////////////////////////
// Within Device 3's process/thread:
// Rendering onto Sync Shared Surface from D3D10.1 Device 1 using D3D10.1 Device 3
result = g_pDXGIKeyedMutex_dev1->AcquireSync(2, timeOut);
// Rendering calls using Device 3
...
result = g_pDXGIKeyedMutex_dev1->ReleaseSync(0);
...

Perhatikan bahwa aplikasi dunia nyata mungkin selalu dirender ke permukaan perantara yang kemudian disalin ke permukaan bersama untuk mencegah satu perangkat yang menunggu di perangkat lain yang berbagi permukaan.

Menggunakan Permukaan Bersama yang Disinkronkan dengan Direct2D dan Direct3D 11

Demikian pula, untuk berbagi antara Direct3D 11 dan Direct3D 10.1 API, permukaan bersama yang disinkronkan dapat dibuat dari perangkat API dan dibagikan dengan perangkat API lainnya, di dalam atau di luar proses.

Aplikasi yang menggunakan Direct2D dapat berbagi perangkat Direct3D 10.1 dan menggunakan permukaan bersama yang disinkronkan untuk beroperasi dengan Direct3D 11 atau perangkat Direct3D 10.1 lainnya, baik milik proses yang sama atau proses yang berbeda. Namun, untuk aplikasi satu proses, rangkaian tunggal, berbagi perangkat adalah metode interoperabilitas yang paling berkinerja tinggi dan efisien antara Direct2D dan Direct3D 10 atau Direct3D 11.

Rasterizer Perangkat Lunak

Permukaan bersama yang disinkronkan tidak didukung ketika aplikasi menggunakan rasterizer perangkat lunak Direct3D atau Direct2D, termasuk rasterizer referensi dan WARP, alih-alih menggunakan akselerasi perangkat keras grafis.

Interoperabilitas antara API berbasis Direct3D 9Ex dan DXGI

API Direct3D 9Ex menyertakan gagasan berbagi permukaan untuk memungkinkan API lain membaca dari permukaan bersama. Untuk berbagi membaca dan menulis ke permukaan bersama Direct3D 9Ex, Anda harus menambahkan sinkronisasi manual ke aplikasi itu sendiri.

Direct3D 9Ex Shared Surfaces Plus Manual Synchronization Helper

Tugas paling mendasar dalam interoperabilitas Direct3D 9Ex dan Direct3D 10 atau 11 adalah melewati satu permukaan dari perangkat pertama (perangkat A) ke yang kedua (perangkat B) sehingga ketika perangkat B memperoleh handel di permukaan, penyajian perangkat A dijamin telah selesai. Oleh karena itu, perangkat B dapat menggunakan permukaan ini tanpa khawatir. Ini sangat mirip dengan masalah produsen-konsumen klasik dan diskusi ini mencontohkan masalah seperti itu. Perangkat pertama yang menggunakan permukaan dan kemudian melepaskannya adalah produsen (Perangkat A), dan perangkat yang awalnya menunggu adalah konsumen (Perangkat B). Setiap aplikasi dunia nyata lebih canggih dari ini, dan akan menyatukan beberapa blok bangunan produsen-konsumen untuk membuat fungsionalitas yang diinginkan.

Blok bangunan produsen-konsumen diimplementasikan di pembantu dengan menggunakan antrean permukaan. Permukaan diantrekan oleh produsen dan diantrekan oleh konsumen. Pembantu memperkenalkan tiga antarmuka COM: ISurfaceQueue, ISurfaceProducer, dan ISurfaceConsumer.

High-Level Gambaran Umum Helper

Objek ISurfaceQueue adalah blok penyusun untuk menggunakan permukaan bersama. Ini dibuat dengan perangkat Direct3D yang diinisialisasi dan deskripsi untuk membuat sejumlah permukaan bersama tetap. Objek antrean mengelola pembuatan sumber daya dan pembukaan kode. Jumlah dan jenis permukaan diperbaiki; setelah permukaan dibuat, aplikasi tidak dapat menambahkan atau menghapusnya.

Setiap instans objek ISurfaceQueue menyediakan semacam jalan satu arah yang dapat digunakan untuk mengirim permukaan dari perangkat yang memproduksi ke perangkat yang mengonsumsi. Beberapa jalan satu arah tersebut dapat digunakan untuk mengaktifkan skenario berbagi permukaan antara perangkat aplikasi tertentu.

Masa Pakai Pembuatan/Objek
Ada dua cara untuk membuat objek antrean: melalui CreateSurfaceQueue, atau melalui metode Klon ISurfaceQueue. Karena antarmukanya adalah objek COM, manajemen masa pakai COM standar berlaku.
Model Produsen/Konsumen
Enqueue (): Produsen memanggil fungsi ini untuk menunjukkan bahwa fungsi ini dilakukan dengan permukaan, yang sekarang dapat tersedia untuk perangkat lain. Setelah kembali dari fungsi ini, perangkat produsen tidak lagi memiliki hak atas permukaan dan tidak aman untuk terus menggunakannya.
Hapus antrean (): Perangkat yang menggunakan memanggil fungsi ini untuk mendapatkan permukaan bersama. API menjamin bahwa setiap permukaan yang telah diantrekan siap digunakan.
Metadata
API mendukung asosiasi metadata dengan permukaan bersama.
Enqueue() memiliki opsi untuk menentukan metadata tambahan yang akan diteruskan ke perangkat yang mengonsumsi. Metadata harus kurang dari maksimum yang diketahui pada waktu pembuatan.
Dequeue() dapat secara opsional meneruskan buffer dan pointer ke ukuran buffer. Antrean mengisi buffer dengan metadata dari panggilan Antrean yang sesuai.
Kloning
Setiap objek ISurfaceQueue memecahkan sinkronisasi satu arah. Kami berasumsi bahwa sebagian besar aplikasi yang menggunakan API ini akan menggunakan sistem tertutup. Sistem tertutup paling sederhana dengan dua perangkat yang mengirim permukaan bolak-balik membutuhkan dua antrean. Objek ISurfaceQueue memiliki metode Clone() untuk memungkinkan untuk membuat beberapa antrean yang semuanya merupakan bagian dari alur yang lebih besar yang sama.
Kloning membuat objek ISurfaceQueue baru dari yang sudah ada, dan berbagi semua sumber daya yang dibuka di antara mereka. Objek yang dihasilkan memiliki permukaan yang sama persis dengan antrean sumber. Antrean kloning dapat memiliki ukuran metadata yang berbeda satu sama lain.
Permukaan
ISurfaceQueue bertanggung jawab untuk membuat dan mengelola permukaannya. Tidak valid untuk mengantrekan permukaan arbitrer. Selain itu, permukaan hanya boleh memiliki satu "pemilik" aktif. Ini harus berada pada antrean tertentu atau digunakan oleh perangkat tertentu. Tidak valid untuk memilikinya pada beberapa antrean atau agar perangkat terus menggunakan permukaan setelah antrean.

Detail API

IsurfaceQueue

Antrean bertanggung jawab untuk membuat dan memelihara sumber daya bersama. Ini juga menyediakan fungsionalitas untuk menautkan beberapa antrean menggunakan Kloning. Antrean memiliki metode yang membuka perangkat produksi dan perangkat yang mengonsumsi. Hanya satu dari masing-masing yang dapat dibuka kapan saja.

Antrean mengekspos API berikut:

API Deskripsi
CreateSurfaceQueue Membuat objek ISurfaceQueue (antrean "root").
ISurfaceQueue::OpenConsumer Mengembalikan antarmuka untuk perangkat yang mengkonsumsi untuk menghapus antrean.
ISurfaceQueue::OpenProducer Mengembalikan antarmuka untuk perangkat pengproduksi yang akan diantrekan.
ISurfaceQueue::Clone Membuat objek ISurfaceQueue yang berbagi permukaan dengan objek antrean akar.

 

CreateSurfaceQueue

typedef struct SURFACE_QUEUE_DESC {
  UINT            Width;
  UINT            Height;
  DXGI_FORMAT     Format;
  UINT            NumSurfaces;
  UINT            MetaDataSize;
  DWORD           Flags;
} SURFACE_QUEUE_DESC;

Anggota

Lebar, Tinggi Dimensi permukaan bersama. Semua permukaan bersama harus memiliki dimensi yang sama.
Format Format permukaan bersama. Semua permukaan bersama harus memiliki format yang sama. Format yang valid bergantung pada perangkat yang akan digunakan, karena pasangan perangkat yang berbeda dapat berbagi jenis format yang berbeda.
NumSurfaces Jumlah permukaan yang merupakan bagian dari antrean. Ini adalah angka tetap.
MetaDataSize Ukuran maksimum buffer metadata.
Bendera Bendera untuk mengontrol perilaku antrean. Lihat Keterangan.

HRESULT CreateSurfaceQueue(
  [in]   SURFACE_QUEUE_DESC *pDesc,
  [in]   IUnknown *pDevice,
  [out]  IDXGIXSurfaceQueue **ppQueue
);

Parameter

pDesc [in] Deskripsi antrean permukaan bersama yang akan dibuat.

pDevice [in] Perangkat yang harus digunakan untuk membuat permukaan bersama. Ini adalah parameter eksplisit karena fitur di Windows Vista. Untuk permukaan yang dibagikan antara Direct3D 9 dan Direct3D 10, permukaan harus dibuat dengan Direct3D 9.

ppQueue [out] Saat kembali, berisi penunjuk ke objek ISurfaceQueue.

Mengembalikan Nilai

Jika pDevice tidak mampu berbagi sumber daya, fungsi ini mengembalikan DXGI_ERROR_INVALID_CALL. Fungsi ini membuat sumber daya. Jika gagal, kesalahan akan ditampilkan. Jika berhasil, ia akan mengembalikan S_OK.

Keterangan

Membuat objek antrean juga membuat semua permukaan. Semua permukaan diasumsikan sebagai target render 2D dan akan dibuat dengan bendera D3D10_BIND_RENDER_TARGET dan D3D10_BIND_SHADER_RESOURCE diatur (atau bendera yang setara untuk runtime yang berbeda).

Pengembang dapat menentukan bendera yang menunjukkan apakah antrean akan diakses oleh beberapa utas. Jika tidak ada bendera yang diatur (Bendera == 0), antrean akan digunakan oleh beberapa utas. Pengembang dapat menentukan akses berutas tunggal, yang menonaktifkan kode sinkronisasi dan memberikan peningkatan performa untuk kasus tersebut. Setiap antrean kloning memiliki bendera sendiri, sehingga dimungkinkan bagi antrean yang berbeda dalam sistem untuk memiliki kontrol sinkronisasi yang berbeda.

Buka Produser

HRESULT OpenProducer(
  [in]   IUnknown *pDevice,
  [out]  IDXGIXSurfaceProducer **ppProducer
);

Parameter

pDevice [in]

Perangkat produsen yang mengantrekan permukaan ke antrean permukaan.

ppProducer [out] Mengembalikan objek ke antarmuka produser.

Mengembalikan Nilai

Jika perangkat tidak mampu berbagi permukaan, mengembalikan DXGI_ERROR_INVALID_CALL.

Buka Konsumen

HRESULT OpenConsumer(
  [in]   IUnknown *pDevice,
  [out]  IDXGIXSurfaceConsumer **ppConsumer
);

Parameter
pDevice [in]
Perangkat konsumen yang menghapus antrean permukaan dari antrean permukaan. ppConsumer [out] Mengembalikan objek ke antarmuka konsumen.

Mengembalikan Nilai

Jika perangkat tidak mampu berbagi permukaan, mengembalikan DXGI_ERROR_INVALID_CALL.

Keterangan

Fungsi ini membuka semua permukaan dalam antrean untuk perangkat input dan menyimpannya dalam cache. Panggilan berikutnya ke Dequeue hanya akan masuk ke cache dan tidak perlu membuka kembali permukaan setiap kali.

Mengkloning IDXGIXSurfaceQueue

typedef struct SHARED_SURFACE_QUEUE_CLONE_DESC {
  UINT         MetaDataSize;
  DWORD        Flags;
} SHARED_SURFACE_QUEUE_CLONE_DESC;

AnggotaMetaDataSize dan Bendera memiliki perilaku yang sama seperti yang mereka lakukan untuk CreateSurfaceQueue.

HRESULT Clone(
  [in]   SHARED_SURFACE_QUEUE_CLONE_DESC *pDesc,
  [out]  IDXGIXSurfaceQueue **ppQueue
);

Parameter

pDesc [in] Struct yang memberikan deskripsi objek Kloning yang akan dibuat. Parameter ini harus diinisialisasi.
ppQueue [out] Mengembalikan objek yang diinisialisasi.

Keterangan

Anda dapat mengkloning dari objek antrean yang ada, bahkan jika itu bukan akarnya.

IDXGIXSurfaceConsumer

HRESULT Dequeue(
  [in]      REFIID    id,
  [out]     void      **ppSurface,
  [in,out]  void      *pBuffer,
  [in,out]  UINT      *pBufferSize,
  [in]      DWORD     dwTimeout
);

Parameter
id [in]
REFIID dari permukaan 2D dari perangkat yang mengonsumsi.

  • Untuk IDirect3DDevice9, REFIID harus __uuidof(IDirect3DTexture9).
  • Untuk ID3D10Device, REFIID harus __uuidof(ID3D10Texture2D).
  • Untuk ID3D11Device, REFIID harus __uuidof(ID3D11Texture2D).

ppSurface [out] Mengembalikan penunjuk ke permukaan.
pBuffer [in, out] Parameter opsional dan jika tidak NULL, saat dikembalikan, berisi metadata yang diteruskan pada panggilan antrean yang sesuai.
pBufferSize [in, out] Ukuran pBuffer, dalam byte. Mengembalikan jumlah byte yang dikembalikan dalam pBuffer. Jika panggilan antrean tidak menyediakan metadata, pBuffer diatur ke 0.
dwTimeout [in] Menentukan nilai batas waktu. Lihat Keterangan untuk detail selengkapnya.

Mengembalikan Nilai

Fungsi ini dapat mengembalikan WAIT_TIMEOUT jika nilai batas waktu ditentukan dan fungsi tidak kembali sebelum nilai waktu habis. Lihat Keterangan. Jika tidak ada permukaan yang tersedia, fungsi mengembalikan dengan ppSurface diatur ke NULL, pBufferSize diatur ke 0 dan nilai yang dikembalikan 0x80070120 (WIN32_TO_HRESULT(WAIT_TIMEOUT)).

Keterangan

API ini dapat memblokir jika antrean kosong. Parameter dwTimeout berfungsi identik dengan API sinkronisasi Windows, seperti WaitForSingleObject. Untuk perilaku non-pemblokiran, gunakan batas waktu 0.

ISurfaceProducer

Antarmuka ini menyediakan dua metode yang memungkinkan aplikasi untuk mengantrekan permukaan. Setelah permukaan diantrekan, penunjuk permukaan tidak lagi valid dan tidak aman untuk digunakan. Satu-satunya tindakan yang harus dilakukan aplikasi dengan pointer adalah melepaskannya.

Metode Deskripsi
ISurfaceProducer::Enqueue Mengantrekan permukaan ke objek antrean. Setelah panggilan ini selesai, produsen dilakukan dengan permukaan dan permukaan siap untuk perangkat lain.
ISurfaceProducer::Flush Digunakan jika aplikasi harus memiliki perilaku non-pemblokiran. Lihat Keterangan untuk detailnya.

 

Masukkan Antrean

HRESULT Enqueue(
  [in]  IUnknown *pSurface,
  [in]  void *pBuffer,
  [in]  UINT BufferSize,
  [in]  DWORD Flags
);

Parameter
pSurface [in]
Permukaan perangkat pengproduksi yang perlu diantrekan. Permukaan ini harus merupakan permukaan yang tidak diantrekan dari jaringan antrean yang sama. pBuffer [in] Parameter opsional, yang digunakan untuk meneruskan metadata. Ini harus menunjuk ke data yang akan diteruskan ke panggilan penghapusan antrean.
BufferSize [in] Ukuran pBuffer, dalam byte.
Bendera [in] Parameter opsional yang mengontrol perilaku fungsi ini. Satu-satunya bendera adalah SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Lihat Komentar untuk Flush. Jika tidak ada bendera yang diteruskan (Bendera == 0), maka perilaku pemblokiran default akan digunakan.

Mengembalikan Nilai

Fungsi ini dapat mengembalikan DXGI_ERROR_WAS_STILL_DRAWING jika bendera SURFACE_QUEUE_FLAG_DO_NOT_WAIT digunakan.

Keterangan

  • Fungsi ini menempatkan permukaan pada antrean. Jika aplikasi tidak menentukan SURFACE_QUEUE_FLAG_DO_NOT_WAIT, fungsi ini memblokir dan akan melakukan sinkronisasi GPU-CPU untuk memastikan bahwa semua penyajian pada permukaan antrean selesai. Jika fungsi ini berhasil, permukaan akan tersedia untuk didequeue. Jika Anda menginginkan perilaku non-pemblokiran, gunakan bendera DO_NOT_WAIT. Lihat Flush() untuk detailnya.
  • Sesuai aturan penghitungan referensi COM, permukaan yang dikembalikan oleh Dequeue akan menjadi AddRef() sehingga aplikasi tidak perlu melakukan ini. Setelah memanggil Enqueue, aplikasi harus Melepaskan permukaan karena tidak lagi menggunakannya.

Flush

HRESULT Flush(
  [in]  DWORD Flags,
  [out] UINT *nSurfaces
);

Parameter
Bendera [in]
Satu-satunya bendera adalah SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Lihat Keterangan. nSurfaces [out] Mengembalikan jumlah permukaan yang masih tertunda dan tidak dibersihkan.

Mengembalikan Nilai

Fungsi ini dapat mengembalikan DXGI_ERROR_WAS_STILL_DRAWING jika bendera SURFACE_QUEUE_FLAG_DO_NOT_WAIT digunakan. Fungsi ini mengembalikan S_OK jika ada permukaan yang berhasil dibersihkan. Fungsi ini mengembalikan DXGI_ERROR_WAS_STILL_DRAWING hanya jika tidak ada permukaan yang dibersihkan. Bersama-sama, nilai pengembalian dan nSurfaces menunjukkan kepada aplikasi pekerjaan apa yang telah dilakukan dan jika ada pekerjaan yang tersisa untuk dilakukan.

Keterangan

Flush bermakna hanya jika panggilan sebelumnya untuk mengantre menggunakan bendera DO_NOT_WAIT; jika tidak, itu akan menjadi no-op. Jika panggilan ke antrean menggunakan bendera DO_NOT_WAIT, antrean segera kembali dan sinkronisasi GPU-CPU tidak dijamin. Permukaan masih dianggap antrean, perangkat pengproduksi tidak dapat terus menggunakannya, tetapi tidak tersedia untuk dihapus antrean. Untuk mencoba menerapkan permukaan untuk menghapus antrean, Flush harus dipanggil. Flush mencoba untuk melakukan semua permukaan yang saat ini diantrekan. Jika tidak ada bendera yang diteruskan ke Flush, bendera akan memblokir dan menghapus seluruh antrean, menyiapkan semua permukaan di dalamnya untuk dequeue. Jika bendera DO_NOT_WAIT digunakan, antrean akan memeriksa permukaan untuk melihat apakah salah satu dari mereka siap; langkah ini tidak memblokir. Permukaan yang telah menyelesaikan sinkronisasi GPU-CPU akan siap untuk perangkat konsumen. Permukaan yang masih tertunda tidak akan terpengaruh. Fungsi mengembalikan jumlah permukaan yang masih perlu dibersihkan.

Catatan

Flush tidak akan merusak semantik antrean. API menjamin bahwa permukaan yang diantrekan terlebih dahulu akan dilakukan sebelum permukaan diantrekan nanti, terlepas dari kapan sinkronisasi GPU-CPU terjadi.

 

Direct3D 9Ex dan DXGI Interop Helper: Cara Menggunakan

Kami mengharapkan sebagian besar kasus penggunaan melibatkan dua perangkat yang berbagi sejumlah permukaan. Karena ini juga merupakan skenario paling sederhana, makalah ini merinci cara menggunakan API untuk mencapai tujuan ini, mendiskusikan variasi non-pemblokiran, dan berakhir dengan bagian singkat tentang inisialisasi untuk tiga perangkat.

Dua Perangkat

Contoh aplikasi yang menggunakan pembantu ini dapat menggunakan Direct3D 9Ex dan Direct3D 11 bersama-sama. Aplikasi dapat memproses konten dengan kedua perangkat, dan menyajikan konten menggunakan Direct3D 9. Pemrosesan dapat berarti merender konten, mendekode video, menjalankan shader komputasi, dan sebagainya. Untuk setiap bingkai, aplikasi akan terlebih dahulu memproses dengan Direct3D 11, kemudian memproses dengan Direct3D 9, dan akhirnya hadir dengan Direct3D 9. Selanjutnya, pemrosesan dengan Direct3D 11 akan menghasilkan beberapa metadata yang perlu dikonsumsi direct3D 9. Bagian ini mencakup penggunaan pembantu dalam tiga bagian yang sesuai dengan urutan ini: Inisialisasi, Perulangan Utama, dan Pembersihan.

Inisialisasi
Inisialisasi melibatkan langkah-langkah berikut:

  1. Menginisialisasi kedua perangkat.
  2. Buat Antrean Akar: m_11to9Queue.
  3. Kloning dari Antrean Akar: m_9to11Queue.
  4. Panggil OpenProducer/OpenConsumer pada kedua antrean.

Nama antrean menggunakan angka 9 dan 11 untuk menunjukkan API mana yang merupakan produsen dan yang merupakan konsumen: m_producerkeAntreankonsumen. Dengan demikian, m_11to9Queue menunjukkan antrean di mana perangkat Direct3D 11 menghasilkan permukaan yang dikonsumsi perangkat Direct3D 9. Demikian pula, m_9to11Queue menunjukkan antrean yang Direct3D 9 menghasilkan permukaan yang dikonsumsi Direct3D 11.
Antrean Akar awalnya penuh dan semua antrean kloning awalnya kosong. Ini seharusnya tidak menjadi masalah untuk aplikasi kecuali untuk siklus pertama Antrean dan Penghapusan Antrean dan ketersediaan metadata. Jika antrean meminta metadata tetapi tidak ada yang ditetapkan (baik karena awalnya tidak ada atau antrean tidak mengatur apa pun), penghapusan antrean melihat bahwa tidak ada metadata yang diterima.

  1. Menginisialisasi kedua perangkat.

    m_pD3D9Device = InitializeD3D9ExDevice();
    m_pD3D11Device = InitializeD3D11Device();
    
  2. Buat Antrean Akar.
    Langkah ini juga menciptakan permukaan. Pembatasan ukuran dan format identik dengan membuat sumber daya bersama apa pun. Ukuran buffer metadata diperbaiki pada waktu pembuatan, dan dalam hal ini, kita hanya akan melewati UINT.
    Antrean harus dibuat dengan sejumlah permukaan tetap. Performa akan bervariasi tergantung pada skenarionya. Memiliki beberapa permukaan meningkatkan kemungkinan perangkat sibuk. Misalnya, jika hanya ada satu permukaan, maka tidak akan ada paralelisasi antara kedua perangkat. Di sisi lain, meningkatkan jumlah permukaan meningkatkan jejak memori, yang dapat menurunkan performa. Contoh ini menggunakan dua permukaan.

    SURFACE_QUEUE_DESC Desc;
    Desc.Width        = 640;
    Desc.Height       = 480;
    Desc.Format       = DXGI_FORMAT_R16G16B16A16_FLOAT;
    Desc.NumSurfaces  = 2;
    Desc.MetaDataSize = sizeof(UINT);
    Desc.Flags        = 0;
    
    CreateSurfaceQueue(&Desc, m_pD3D9Device, &m_11to9Queue);
    
  3. Kloning Antrean Akar.
    Setiap antrean kloning harus menggunakan permukaan yang sama tetapi dapat memiliki ukuran buffer metadata yang berbeda dan bendera yang berbeda. Dalam hal ini, tidak ada metadata dari Direct3D 9 ke Direct3D 11.

    SURFACE_QUEUE_CLONE_DESC Desc;
    Desc.MetaDataSize = 0;
    Desc.Flags        = 0;
    
    m_11to9Queue->Clone(&Desc, &m_9to11Queue);
    
  4. Buka Perangkat Produsen dan Konsumen.
    Aplikasi harus melakukan langkah ini sebelum memanggil Enqueue dan Dequeue. Membuka produsen dan konsumen mengembalikan antarmuka yang berisi API antrean/dequeue.

    // Open for m_p9to11Queue.
    m_p9to11Queue->OpenProducer(m_pD3D9Device, &m_pD3D9Producer);
    m_p9to11Queue->OpenConsumer(m_pD3D11Device, &m_pD3D11Consumer);
    
    // Open for m_p11to9Queue.
    m_p11to9Queue->OpenProducer(m_pD3D11Device, &m_pD3D11Producer);
    m_p11to9Queue->OpenConsumer(m_pD3D9Device, &m_pD3D9Consumer);
    

Perulangan Utama
Penggunaan antrean dimodelkan setelah masalah produsen/konsumen klasik. Pikirkan ini dari perspektif per perangkat. Setiap perangkat harus melakukan langkah-langkah ini: menghapus antrean untuk mendapatkan permukaan dari antrean yang mengonsumsi, memproses di permukaan, dan kemudian mengantre ke antrean memproduksinya. Untuk perangkat Direct3D 11, penggunaan Direct3D 9 hampir identik.

// Direct3D 9 Device.
IDirect3DTexture9* pTexture9 = NULL;
REFIID             surfaceID9 = _uuidof(IDirect3DTexture9);
UINT               metaData;
UINT               metaDataSize;
while (!done)
{
    // Dequeue surface.
    m_pD3D9Consumer->Dequeue(surfaceID9, (void**)&pSurface9,
                             &metaData, &metaDataSize, INFINITE);

    // Process the surface.
    ProcessD3D9(pSurface9);

    // Present the surface using the meta data.
    PresentD3D9(pSurface9, metaData, metaDataSize);

    // Enqueue surface.
    m_pD3D9Producer->Enqueue(pSurface9, NULL, 0, 0);
}

Sedang Membersihkan
Langkah ini sangat mudah. Selain langkah-langkah normal untuk membersihkan API Direct3D, aplikasi harus merilis antarmuka COM yang dikembalikan.

m_pD3D9Producer->Release();
m_pD3D9Consumer->Release();
m_pD3D11Producer->Release();
m_pD3D11Consumer->Release();
m_p9to11Queue->Release();
m_p11to9Queue->Release();

Penggunaan Non-Pemblokiran

Contoh sebelumnya masuk akal untuk kasus penggunaan multithread di mana setiap perangkat memiliki utasnya sendiri. Contohnya menggunakan versi pemblokiran API: INFINITE untuk waktu habis, dan tidak ada bendera untuk diantrekan. Jika Anda ingin menggunakan pembantu dengan cara yang tidak memblokir, Anda hanya perlu membuat beberapa perubahan. Bagian ini menunjukkan penggunaan non-pemblokiran dengan kedua perangkat pada satu utas.

Inisialisasi
Inisialisasi identik kecuali untuk bendera. Karena aplikasi berutas tunggal, gunakan bendera tersebut untuk pembuatan. Ini menonaktifkan beberapa kode sinkronisasi, yang berpotensi meningkatkan performa.

SURFACE_QUEUE_DESC Desc;
Desc.Width        = 640;
Desc.Height       = 480;
Desc.Format       = DXGI_FORMAT_R16G16B16A16_FLOAT;
Desc.NumSurfaces  = 2;
Desc.MetaDataSize = sizeof(UINT);
Desc.Flags        = SURFACE_QUEUE_FLAG_SINGLE_THREADED;

CreateSurfaceQueue(&Desc, m_pD3D9Device, &m_11to9Queue);
SURFACE_QUEUE_CLONE_DESC Desc;
Desc.MetaDataSize = 0;
Desc.Flags        = SURFACE_QUEUE_FLAG_SINGLE_THREADED;

m_11to9Queue->Clone(&Desc, &m_9to11Queue);

Membuka perangkat produsen dan konsumen sama seperti dalam contoh pemblokiran.
Menggunakan Antrean
Ada banyak cara menggunakan antrean dengan cara yang tidak memblokir dengan berbagai karakteristik performa. Contoh berikut sederhana tetapi memiliki performa yang buruk karena pemintalan dan polling yang berlebihan. Terlepas dari masalah ini, contoh menunjukkan cara menggunakan pembantu. Pendekatannya adalah untuk terus-menerus duduk dalam perulangan dan penghapusan antrean, proses, antrean, dan siram. Jika salah satu langkah gagal karena sumber daya tidak tersedia, aplikasi hanya mencoba lagi perulangan berikutnya.

// Direct3D 11 Device.
ID3D11Texture2D* pSurface11 = NULL;
REFIID           surfaceID11 = __uuidof(ID3D11Texture2D);
UINT             metaData;
while (!done)
{
    //
    // D3D11 Portion.
    //

    // Dequeue surface.
    hr = m_pD3D11Consumer->Dequeue(surfaceID11,
                                   (void**)&pSurface11,
                                   NULL, 0, 0);
    // Only continue if we got a surface.
    if (SUCCEEDED(hr))
    {
        // Process the surface and return some meta data.
        ProcessD3D11(pSurface11, &metaData);

        // Enqueue surface.
        m_pD3D11Producer->Enqueue(pSurface11, &metaData,
                                  sizeof(UINT),
                                  SURFACE_QUEUE_FLAG_DO_NOT_WAIT);
    }
    // Flush the queue to check if any surfaces completed.
    m_pD3D11Producer->Flush(NULL,SURFACE_QUEUE_FLAG_DO_NOT_WAIT);

    //
    // Do the same with the Direct3D 9 Device.
    //

    // Dequeue surface.
    hr = m_pD3D9Consumer->Dequeue(surfaceID9,
                                  (void**)&pSurface9,
                                  &metaData,
                                  &metaDataSize, 0);
    // Only continue if we got a surface.
    if (SUCCEEDED(hr)))
    {
        // Process the surface.
        ProcessD3D9(pSurface9);

        // Present the surface using the meta data.
        PresentD3D9(pSurface9, metaData, metaDataSize);

        // Enqueue surface.
        m_pD3D9Producer->Enqueue(pSurface9, NULL, 0,
                                 SURFACE_QUEUE_FLAG_DO_NOT_WAIT);
    }
    // Flush the queue to check if any surfaces completed.
    m_pD3D9Producer->Flush(NULL,SURFACE_QUEUE_FLAG_DO_NOT_WAIT);
}

Solusi yang lebih kompleks dapat memeriksa nilai pengembalian dari antrean dan dari pembilasan untuk menentukan apakah pembilasan diperlukan.

Tiga Perangkat

Memperluas contoh sebelumnya untuk mencakup beberapa perangkat sangat mudah. Kode berikut melakukan inisialisasi. Setelah objek Produsen/Konsumen dibuat, kode untuk menggunakannya sama. Contoh ini memiliki tiga perangkat dan oleh karena itu tiga antrean. Permukaan mengalir dari Direct3D 9 ke Direct3D 10 ke Direct3D 11.

SURFACE_QUEUE_DESC Desc;
Desc.Width        = 640;
Desc.Height       = 480;
Desc.Format       = DXGI_FORMAT_R16G16B16A16_FLOAT;
Desc.NumSurfaces  = 2;
Desc.MetaDataSize = sizeof(UINT);
Desc.Flags        = 0;

SURFACE_QUEUE_CLONE_DESC Desc;
Desc.MetaDataSize = 0;
Desc.Flags        = 0;

CreateSurfaceQueue(&Desc, m_pD3D9Device, &m_11to9Queue);
m_11to9Queue->Clone(&Desc, &m_9to10Queue);
m_11to9Queue->Clone(&Desc, &m_10to11Queue);

Seperti disebutkan sebelumnya, kloning bekerja dengan cara yang sama, tidak peduli antrean mana yang dikloning. Misalnya, panggilan Kloning kedua bisa saja tidak aktif dari objek m_9to10Queue.

// Open for m_p9to10Queue.
m_p9to10Queue->OpenProducer(m_pD3D9Device, &m_pD3D9Producer);
m_p9to10Queue->OpenConsumer(m_pD3D10Device, &m_pD3D10Consumer);

// Open for m_p10to11Queue.
m_p10to11Queue->OpenProducer(m_pD3D10Device, &m_pD3D10Producer);
m_p10to11Queue->OpenConsumer(m_pD3D11Device, &m_pD3D11Consumer);

// Open for m_p11to9Queue.
m_p11to9Queue->OpenProducer(m_pD3D11Device, &m_pD3D11Producer);
m_p11to9Queue->OpenConsumer(m_pD3D9Device, &m_pD3D9Consumer);

Kesimpulan

Anda dapat membuat solusi yang menggunakan interoperabilitas untuk menggunakan kekuatan beberapa API DirectX. Interoperabilitas API grafis Windows sekarang menawarkan runtime manajemen permukaan umum DXGI 1.1. Runtime ini memungkinkan dukungan berbagi permukaan yang disinkronkan dalam API yang baru dikembangkan, seperti Direct3D 11, Direct3D 10.1 dan Direct2D. Peningkatan interoperabilitas antara API baru dan API yang ada membantu migrasi aplikasi dan kompatibilitas mundur. API konsumen Direct3D 9Ex dan DXGI 1.1 dapat beroperasi, seperti yang ditunjukkan dengan mekanisme sinkronisasi yang disediakan melalui kode pembantu sampel di Galeri Kode MSDN.