Condividi tramite


Condivisione di surface tra le API grafiche di Windows

Questo argomento offre una panoramica tecnica dell'interoperabilità tramite la condivisione della superficie tra le API grafiche di Windows, tra cui Direct3D 11, Direct2D, DirectWrite, Direct3D 10 e Direct3D 9Ex. Se si ha già una conoscenza approfondita di queste API, questo documento consente di usare più API per eseguire il rendering nella stessa superficie in un'applicazione progettata per i sistemi operativi Windows 7 o Windows Vista. Questo argomento fornisce anche linee guida e puntatori alle procedure consigliate per risorse aggiuntive.

Nota

Per l'interoperabilità direct2D e DirectWrite nel runtime DirectX 11.1, è possibile usare dispositivi Direct2D e contesti di dispositivo per eseguire il rendering direttamente nei dispositivi Direct3D 11.

 

Questo argomento include le sezioni seguenti.

Introduzione

In questo documento, l'interoperabilità dell'API grafica di Windows si riferisce alla condivisione della stessa superficie di rendering con API diverse. Questo tipo di interoperabilità consente alle applicazioni di creare visualizzazioni accattivanti sfruttando più API grafiche di Windows e di semplificare la migrazione a nuove tecnologie mantenendo la compatibilità con le API esistenti.

In Windows 7 (e Windows Vista SP2 con Windows 7 Interop Pack, Vista 7IP), le API per il rendering della grafica sono Direct3D 11, Direct2D, Direct3D 10.1, Direct3D 10.0, Direct3D 9Ex, Direct3D 9c e api Direct3D precedenti, nonché GDI e GDI+. Windows Imaging Component (WIC) e DirectWrite sono tecnologie correlate per l'elaborazione delle immagini e Direct2D esegue il rendering del testo. L'API DirectX Video Acceleration (DXVA), basata su Direct3D 9c e Direct3D 9Ex, viene usata per l'elaborazione video.

Man mano che le API grafiche windows si evolvono verso l'essere basate su Direct3D, Microsoft sta investendo più impegno per garantire l'interoperabilità tra le API. Le NUOVE API Direct3D e le API di livello superiore basate sulle API Direct3D offrono anche il supporto, se necessario per la compatibilità bridging con le API meno recenti. Per illustrare, le applicazioni Direct2D possono usare Direct3D 10.1 condividendo un dispositivo Direct3D 10.1. Inoltre, le API Direct3D 11, Direct2D e Direct3D 10.1 possono sfruttare tutti i vantaggi di DirectX Graphics Infrastructure (DXGI) 1.1, che consente superfici condivise sincronizzate che supportano completamente l'interoperabilità tra queste API. Le API basate su DXGI 1.1 interagiscono con GDI e GDI+ per associazione, ottenendo il contesto di dispositivo GDI da una superficie DXGI 1.1.

La condivisione della superficie non sincronizzata è supportata dal runtime Direct3D 9Ex. Le applicazioni video basate su DXVA possono usare l'helper di interoperabilità Direct3D 9Ex e DXGI per l'interoperabilità DXVA basata su Direct3D 9Ex con Direct3D 11 per lo shader di calcolo oppure può interagire con Direct2D per controlli 2D o rendering del testo. WIC e DirectWrite interagiscono anche con GDI, Direct2D e per associazione, altre API Direct3D.

I runtime Direct3D 10.0, Direct3D 9c e direct3D precedenti non supportano le superfici condivise. Le copie di memoria di sistema continueranno a essere usate per l'interoperabilità con le API basate su GDI o DXGI.

Si noti che gli scenari di interoperabilità all'interno di questo documento fanno riferimento a più API grafiche per il rendering in una superficie di rendering condivisa, anziché alla stessa finestra dell'applicazione. La sincronizzazione per API separate destinate a superfici diverse che vengono quindi composte nella stessa finestra non rientra nell'ambito di questo documento.

Panoramica dell'interoperabilità delle API

L'interoperabilità di condivisione della superficie delle API grafiche di Windows può essere descritta in termini di scenari da API a API e dalle funzionalità di interoperabilità corrispondenti. A partire da Windows 7 e a partire da Windows Vista SP2 con 7IP, le nuove API e i runtime associati includono Direct2D e tecnologie correlate: Direct3D 11 e DXGI 1.1. Le prestazioni GDI sono state migliorate anche in Windows 7. Direct3D 10.1 è stato introdotto in Windows Vista SP1. Il diagramma seguente illustra il supporto dell'interoperabilità tra le API.

diagramma del supporto dell'interoperabilità tra le API grafiche di Windows

In questo diagramma le frecce mostrano scenari di interoperabilità in cui la stessa superficie può essere accessibile dalle API connesse. Le frecce blu indicano meccanismi di interoperabilità introdotti in Windows Vista. Le frecce verdi indicano il supporto dell'interoperabilità per le nuove API o miglioramenti che consentono alle API meno recenti di interagire con le API più recenti. Ad esempio, le frecce verdi rappresentano la condivisione dei dispositivi, il supporto della superficie condivisa sincronizzata, l'helper di sincronizzazione Direct3D 9Ex/DXGI e il recupero di un contesto di dispositivo GDI da una superficie compatibile.

Scenari di interoperabilità

A partire da Windows 7 e Windows Vista 7IP, le offerte mainstream delle API grafiche di Windows supportano il rendering di più API nella stessa superficie DXGI 1.1.

Direct3D 11, Direct3D 10.1, Direct2D - Interoperabilità tra loro

Le API Direct3D 11, Direct3D 10.1 e Direct2D (e le relative API come DirectWrite e WIC) possono interagire tra loro usando la condivisione dei dispositivi Direct3D 10.1 o le superfici condivise sincronizzate.

Condivisione di dispositivi Direct3D 10.1 con Direct2D

La condivisione dei dispositivi tra Direct2D e Direct3D 10.1 consente a un'applicazione di usare entrambe le API per eseguire facilmente ed efficientemente il rendering nella stessa superficie DXGI 1.1, usando lo stesso oggetto dispositivo Direct3D sottostante. Direct2D offre la possibilità di chiamare le API Direct2D usando un dispositivo Direct3D 10.1 esistente, sfruttando il fatto che Direct2D è basato su runtime Direct3D 10.1 e DXGI 1.1. I frammenti di codice seguenti illustrano come Direct2D ottiene la destinazione di rendering del dispositivo Direct3D 10.1 da una superficie DXGI 1.1 associata al dispositivo. La destinazione di rendering del dispositivo Direct3D 10.1 può eseguire chiamate di disegno Direct2D tra le API BeginDraw e EndDraw.

// 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);

Osservazioni:

  • Il dispositivo Direct3D 10.1 associato deve supportare il formato BGRA. Il dispositivo è stato creato chiamando D3D10CreateDevice1 con il parametro D3D10_CREATE_DEVICE_BGRA_SUPPORT. Il formato BGRA è supportato a partire dal livello di funzionalità Direct3D 10 9.1.
  • L'applicazione non deve creare più ID2D1RenderTargets associati allo stesso dispositivo Direct3D10.1.
  • Per ottenere prestazioni ottimali, mantenere sempre almeno una risorsa, ad esempio trame o superfici associate al dispositivo.

La condivisione dei dispositivi è adatta per l'utilizzo a thread singolo in-process di un dispositivo di rendering condiviso dalle API di rendering Direct3D 10.1 e Direct2D. Le superfici condivise sincronizzate consentono l'uso multithreading, in-process e out-of-process di più dispositivi di rendering usati dalle API Direct3D 10.1, Direct2D e Direct3D 11.

Un altro metodo di interoperabilità Direct3D 10.1 e Direct2D consiste nell'usare ID3D1RenderTarget::CreateSharedBitmap, che crea un oggetto ID2D1Bitmap da IDXGISurface. È possibile scrivere una scena Direct3D10.1 nella bitmap ed eseguirne il rendering con Direct2D. Per altre informazioni, vedere Metodo ID2D1RenderTarget::CreateSharedBitmap.

Rasterizzazione del software Direct2D

La condivisione di dispositivi con Direct3D 10.1 non è supportata quando si usa il renderer software Direct2D, ad esempio, specificando D2D1_RENDER_TARGET_USAGE_FORCE_SOFTWARE_RENDERING in D2D1_RENDER_TARGET_USAGE quando si crea una destinazione di rendering Direct2D.

Direct2D può usare il rasterizzatore software WARP10 per condividere il dispositivo con Direct3D 10 o Direct3D 11, ma le prestazioni diminuisce significativamente.

DXGI 1.1 Superfici condivise sincronizzate

Le API Direct3D 11, Direct3D 10.1 e Direct2D usano tutti DXGI 1.1, che fornisce la funzionalità per sincronizzare la lettura e la scrittura nella stessa superficie di memoria video (DXGISurface1) di due o più dispositivi Direct3D. I dispositivi di rendering che usano superfici condivise sincronizzate possono essere dispositivi Direct3D 10.1 o Direct3D 11, ognuno in esecuzione nello stesso processo o tra processi.

Le applicazioni possono usare superfici condivise sincronizzate per interagire tra qualsiasi dispositivo basato su DXGI 1.1, ad esempio Direct3D 11 e Direct3D 10.1 o tra Direct3D 11 e Direct2D, ottenendo il dispositivo Direct3D 10.1 dall'oggetto di destinazione di rendering Direct2D.

Nelle API Direct3D 10.1 e successive, per usare DXGI 1.1, assicurarsi che il dispositivo Direct3D venga creato usando un oggetto adattatore DXGI 1.1, enumerato dall'oggetto factory DXGI 1.1. Chiamare CreateDXGIFactory1 per creare l'oggetto IDXGIFactory1 e EnumAdapters1 per enumerare l'oggetto IDXGIAdapter1. L'oggetto IDXGIAdapter1 deve essere passato come parte della chiamata D3D10CreateDevice o D3D10CreateDeviceAndSwapChain. Per altre informazioni sulle API DXGI 1.1, vedere la Guida alla programmazione per DXGI.

API

D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX
Quando si crea la risorsa condivisa sincronizzata, impostare D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX in 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
Consente di sincronizzare la risorsa creata usando le API IDXGIKeyedMutex::AcquireSync e ReleaseSync. Le API Direct3D 10.1 seguenti per la creazione di risorse che accettano tutti un parametro D3D10_RESOURCE_MISC_FLAG sono state estese per supportare il nuovo flag.

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

Se una delle funzioni elencate viene chiamata con il set di flag D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX, è possibile eseguire una query sull'interfaccia restituita per un'interfaccia IDXGIKeyedMutex, che implementa le API AcquireSync e ReleaseSync per sincronizzare l'accesso alla superficie. Il dispositivo che crea la superficie e qualsiasi altro dispositivo che apre la superficie (usando OpenSharedResource) è necessario per chiamare IDXGIKeyedMutex::AcquireSync prima di qualsiasi comando di rendering sulla superficie e IDXGIKeyedMutex::ReleaseSync al termine del rendering.
I dispositivi WARP e REF non supportano le risorse condivise. Se si tenta di creare una risorsa con questo flag in un dispositivo WARP o REF, il metodo create restituirà un codice di errore E_OUTOFMEMORY.
INTERFACCIA IDXGIKEYEDMUTEX
Una nuova interfaccia in DXGI 1.1, IDXGIKeyedMutex, rappresenta un mutex con chiave, che consente l'accesso esclusivo a una risorsa condivisa usata da più dispositivi. Per la documentazione di riferimento su questa interfaccia e i relativi due metodi, AcquireSync e ReleaseSync, vedere IDXGIKeyedMutex.

Esempio: Condivisione della superficie sincronizzata tra due dispositivi Direct3D 10.1

L'esempio seguente illustra la condivisione di una superficie tra due dispositivi Direct3D 10.1. La superficie condivisa sincronizzata viene creata da un dispositivo 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;

Lo stesso dispositivo Direct3D10.1 può ottenere la superficie condivisa sincronizzata per il rendering chiamando AcquireSync, quindi rilasciando la superficie per il rendering dell'altro dispositivo chiamando ReleaseSync. Quando non si condivide la superficie condivisa sincronizzata con qualsiasi altro dispositivo Direct3D, l'autore può ottenere e rilasciare la superficie condivisa sincronizzata (per avviare e terminare il rendering) acquisendo e rilasciando usando lo stesso valore della chiave.

// 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;

Il secondo dispositivo Direct3D10.1 può ottenere la superficie condivisa sincronizzata per il rendering chiamando AcquireSync, quindi rilasciando la superficie per il rendering del primo dispositivo chiamando ReleaseSync. Si noti che il dispositivo 2 è in grado di acquisire la superficie condivisa sincronizzata usando lo stesso valore di chiave specificato nella chiamata ReleaseSync dal dispositivo 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;

Altri dispositivi che condividono la stessa superficie possono assumere turni di acquisizione e rilascio della superficie usando chiavi aggiuntive, come illustrato nelle chiamate seguenti.

// 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);
...

Si noti che un'applicazione reale potrebbe sempre eseguire il rendering in una superficie intermedia che viene quindi copiata nella superficie condivisa per impedire a qualsiasi dispositivo in attesa su un altro dispositivo che condivide la superficie.

Uso delle superfici condivise sincronizzate con Direct2D e Direct3D 11

Analogamente, per la condivisione tra le API Direct3D 11 e Direct3D 10.1, è possibile creare una superficie condivisa sincronizzata da un dispositivo API e condividerla con gli altri dispositivi API, in o fuori processo.

Le applicazioni che usano Direct2D possono condividere un dispositivo Direct3D 10.1 e usare una superficie condivisa sincronizzata per interagire con Direct3D 11 o altri dispositivi Direct3D 10.1, indipendentemente dal fatto che appartengano allo stesso processo o a processi diversi. Tuttavia, per le applicazioni a thread singolo, la condivisione dei dispositivi è il metodo più efficiente e ad alte prestazioni di interoperabilità tra Direct2D e Direct3D 10 o Direct3D 11.

Rasterizzatore software

Le superfici condivise sincronizzate non sono supportate quando le applicazioni usano rasterizzatori software Direct3D o Direct2D, inclusi il rasterizzatore di riferimento e WARP, anziché usare l'accelerazione hardware grafica.

Interoperabilità tra le API basate su Direct3D 9Ex e DXGI

Le API Direct3D 9Ex includevano la nozione di condivisione della superficie per consentire ad altre API di leggere dalla superficie condivisa. Per condividere la lettura e la scrittura in una superficie condivisa Direct3D 9Ex, è necessario aggiungere la sincronizzazione manuale all'applicazione stessa.

Direct3D 9Ex Shared Surface plus Manual Synchronization Helper

L'attività più fondamentale in Direct3D 9Ex e Direct3D 10 o 11 sta passando una singola superficie dal primo dispositivo (dispositivo A) al secondo (dispositivo B) in modo che quando il dispositivo B acquisisce un handle sulla superficie, il rendering del dispositivo A è garantito che sia stato completato. Pertanto, il dispositivo B può usare questa superficie senza preoccuparsi. Questo è molto simile al problema classico producer-consumer e questa discussione modella il problema in questo modo. Il primo dispositivo che usa la superficie e quindi lo rimette in gioco è il producer (Device A) e il dispositivo che inizialmente è in attesa è il consumer (Dispositivo B). Qualsiasi applicazione reale è più sofisticata di questa e concatena più blocchi predefiniti producer-consumer per creare la funzionalità desiderata.

I blocchi predefiniti producer-consumer vengono implementati nell'helper usando una coda di superfici. Le superfici vengono accodate dal produttore e dequeuate dal consumer. L'helper introduce tre interfacce COM: ISurfaceQueue, ISurfaceProducer e ISurfaceConsumer.

Panoramica generale dell'helper

L'oggetto ISurfaceQueue è il blocco predefinito per l'utilizzo delle superfici condivise. Viene creato con un dispositivo Direct3D inizializzato e una descrizione per creare un numero fisso di superfici condivise. L'oggetto queue gestisce la creazione di risorse e l'apertura del codice. Il numero e il tipo di superfici sono fissi; una volta create le superfici, l'applicazione non può aggiungerle o rimuoverle.

Ogni istanza dell'oggetto ISurfaceQueue fornisce una sorta di strada unidirezionale che può essere usata per inviare superfici dal dispositivo di produzione al dispositivo che utilizza. È possibile usare più strade unidirezionale per abilitare scenari di condivisione della superficie tra dispositivi di applicazioni specifiche.

Durata creazione/oggetto
Esistono due modi per creare l'oggetto coda: tramite CreateSurfaceQueue o tramite il metodo Clone di ISurfaceQueue. Poiché le interfacce sono oggetti COM, viene applicata la gestione della durata COM standard.
Modello producer/consumer
Accodamento (): il producer chiama questa funzione per indicare che viene eseguita con la superficie, che ora può diventare disponibile per un altro dispositivo. Al ritorno da questa funzione, il dispositivo producer non dispone più dei diritti per la superficie e non è sicuro continuare a usarlo.
Dequeue (): il dispositivo che usa chiama questa funzione per ottenere una superficie condivisa. L'API garantisce che tutte le superfici dequeuate siano pronte per l'uso.
Metadati UFX
L'API supporta l'associazione dei metadati alle superfici condivise.
Enqueue() ha la possibilità di specificare metadati aggiuntivi che verranno passati al dispositivo che utilizza. I metadati devono essere inferiori a un massimo noto in fase di creazione.
Dequeue() può facoltativamente passare un buffer e un puntatore alle dimensioni del buffer. La coda riempie il buffer con i metadati della chiamata accodamento corrispondente.
Clonazione
Ogni oggetto ISurfaceQueue risolve una sincronizzazione unidirezionale. Si presuppone che la maggior parte delle applicazioni che usano questa API userà un sistema chiuso. Il sistema chiuso più semplice con due dispositivi che inviano superfici avanti e indietro richiede due code. L'oggetto ISurfaceQueue ha un metodo Clone() per consentire la creazione di più code che fanno parte della stessa pipeline più grande.
Clone crea un nuovo oggetto ISurfaceQueue da un oggetto esistente e condivide tutte le risorse aperte tra di esse. L'oggetto risultante ha esattamente le stesse superfici della coda di origine. Le code clonate possono avere dimensioni di metadati diverse l'una dall'altra.
di lavoro
ISurfaceQueue si assume la responsabilità di creare e gestire le sue superfici. Non è valido accodare superfici arbitrarie. Inoltre, una superficie deve avere un solo "proprietario" attivo. Deve trovarsi in una coda specifica o essere usata da un dispositivo specifico. Non è valido averlo su più code o per consentire ai dispositivi di continuare a usare la superficie dopo l'accodamento.

Dettagli API

IsurfaceQueue

La coda è responsabile della creazione e della gestione delle risorse condivise. Fornisce inoltre la funzionalità per concatenare più code usando Clone. La coda include metodi che aprono il dispositivo di produzione e un dispositivo che utilizza. È possibile aprire una sola di ognuna in qualsiasi momento.

La coda espone le API seguenti:

API Descrizione
CreateSurfaceQueue Crea un oggetto ISurfaceQueue (la coda "radice").
ISurfaceQueue::OpenConsumer Restituisce un'interfaccia per l'utilizzo del dispositivo da rimuovere dalla coda.
ISurfaceQueue::OpenProducer Restituisce un'interfaccia per l'accodamento del dispositivo di produzione.
ISurfaceQueue::Clone Crea un oggetto ISurfaceQueue che condivide le superfici con l'oggetto coda radice.

 

CreateSurfaceQueue

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

Membri

Width, Height Le dimensioni delle superfici condivise. Tutte le superfici condivise devono avere le stesse dimensioni.
FormatTa formato delle superfici condivise. Tutte le superfici condivise devono avere lo stesso formato. I formati validi dipendono dai dispositivi che verranno usati, perché coppie di dispositivi diverse possono condividere tipi di formato diversi.
NumSurfaces Numero di superfici che fanno parte della coda. Si tratta di un numero fisso.
MetaDataSize Dimensioni massime del buffer di metadati.
Flags Flags per controllare il comportamento della coda. Vedere la sezione Osservazioni.

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

Parametri

pDesc [in] Descrizione della coda della superficie condivisa da creare.

pDevice [in] Dispositivo che deve essere usato per creare le superfici condivise. Si tratta di un parametro esplicito a causa di una funzionalità in Windows Vista. Per le superfici condivise tra Direct3D 9 e Direct3D 10, le superfici devono essere create con Direct3D 9.

ppQueue [out] In caso di restituzione, contiene un puntatore all'oggetto ISurfaceQueue.

Valori restituiti

Se pDevice non è in grado di condividere le risorse, questa funzione restituisce DXGI_ERROR_INVALID_CALL. Questa funzione crea le risorse. Se ha esito negativo, restituisce un errore. Se ha esito positivo, restituisce S_OK.

Osservazioni:

La creazione dell'oggetto queue crea anche tutte le superfici. Si presuppone che tutte le superfici siano destinazioni di rendering 2D e verranno create con i flag D3D10_BIND_RENDER_TARGET e D3D10_BIND_SHADER_RESOURCE impostati (o i flag equivalenti per i diversi runtime).

Lo sviluppatore può specificare un flag che indica se la coda sarà accessibile da più thread. Se non vengono impostati flag (Flag == 0), la coda verrà usata da più thread. Lo sviluppatore può specificare l'accesso a thread singolo, che disattiva il codice di sincronizzazione e offre un miglioramento delle prestazioni per tali casi. Ogni coda clonata ha un proprio flag, quindi è possibile che code diverse nel sistema dispongano di controlli di sincronizzazione diversi.

Aprire un producer

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

Parametri

pDevice [in]

Dispositivo producer che accoda le superfici nella coda di superficie.

ppProducer [out] Restituisce un oggetto all'interfaccia producer.

Valori restituiti

Se il dispositivo non è in grado di condividere le superfici, restituisce DXGI_ERROR_INVALID_CALL.

Aprire un consumer

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

Parametri
pDevice [in]
Dispositivo consumer che dequeue le superfici dalla coda di superficie. ppConsumer [out] Restituisce un oggetto all'interfaccia consumer.

Valori restituiti

Se il dispositivo non è in grado di condividere le superfici, restituisce DXGI_ERROR_INVALID_CALL.

Osservazioni:

Questa funzione apre tutte le superfici nella coda per il dispositivo di input e le memorizza nella cache. Le chiamate successive a Dequeue verranno semplicemente visualizzate nella cache e non dovranno riaprire le superfici ogni volta.

Clonazione di un IDXGIXSurfaceQueue

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

I membri MetaDataSize e Flag hanno lo stesso comportamento di createSurfaceQueue.

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

Parametri

pDesc [in] struct che fornisce una descrizione dell'oggetto Clone da creare. Questo parametro deve essere inizializzato.
ppQueue [out] Restituisce l'oggetto inizializzato.

Osservazioni:

È possibile clonare da qualsiasi oggetto coda esistente, anche se non è la radice.

IDXGIXSurfaceConsumer

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

Parametri
id [in]
REFIID di una superficie 2D del dispositivo che utilizza.

  • Per IDirect3DDevice9, refiid deve essere __uuidof(IDirect3DTexture9).
  • Per un ID3D10Device, REFIID deve essere __uuidof(ID3D10Texture2D).
  • Per un ID3D11Device, REFIID deve essere __uuidof(ID3D11Texture2D).

ppSurface [out] Restituisce un puntatore alla superficie.
pBuffer [in, out] Parametro facoltativo e, in caso contrario , NULL, contiene i metadati passati nella chiamata di accodamento corrispondente.
pBufferSize [in, out] Dimensioni di pBuffer, in byte. Restituisce il numero di byte restituiti in pBuffer. Se la chiamata di accodamento non ha fornito metadati, pBuffer è impostato su 0.
dwTimeout [in] Specifica un valore di timeout. Per altri dettagli, vedere la sezione Osservazioni.

Valori restituiti

Questa funzione può restituire WAIT_TIMEOUT se viene specificato un valore di timeout e la funzione non restituisce prima del valore di timeout. Vedere la sezione Osservazioni. Se non sono disponibili superfici, la funzione restituisce con ppSurface impostato su NULL, pBufferSize impostato su 0 e il valore restituito è 0x80070120 (WIN32_TO_HRESULT(WAIT_TIMEOUT)).

Osservazioni:

Questa API può bloccarsi se la coda è vuota. Il parametro dwTimeout funziona in modo identico alle API di sincronizzazione di Windows, ad esempio WaitForSingleObject. Per il comportamento non di blocco, usare un timeout pari a 0.

ISurfaceProducer

Questa interfaccia fornisce due metodi che consentono all'app di accodare le superfici. Dopo l'accodamento di una superficie, il puntatore di superficie non è più valido e non è sicuro da usare. L'unica azione che l'applicazione deve eseguire con il puntatore consiste nel rilasciarla.

metodo Descrizione
ISurfaceProducer::Enqueue Accoda una superficie all'oggetto queue. Al termine di questa chiamata, il produttore viene eseguito con la superficie e la superficie è pronta per un altro dispositivo.
ISurfaceProducer::Flush Viene usato se le applicazioni devono avere un comportamento non di blocco. Pe altri dettagli, vedere la sezione Osservazioni.

 

Enqueue

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

Parametri
pSurface [in]
Superficie del dispositivo di produzione che deve essere accodato. Questa superficie deve essere una superficie dequeued dalla stessa rete di code. pBuffer [in] Parametro facoltativo, usato per passare i metadati. Deve puntare ai dati che verranno passati alla chiamata di rimozione dalla coda.
BufferSize [in] Dimensioni di pBuffer, in byte.
Flag [ in] Parametro facoltativo che controlla il comportamento di questa funzione. L'unico flag è SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Vedere le osservazioni per Flush. Se non viene passato alcun flag (Flag == 0), viene usato il comportamento di blocco predefinito.

Valori restituiti

Questa funzione può restituire DXGI_ERROR_WAS_STILL_DRAWING se viene usato un flag SURFACE_QUEUE_FLAG_DO_NOT_WAIT.

Osservazioni:

  • Questa funzione inserisce la superficie nella coda. Se l'applicazione non specifica SURFACE_QUEUE_FLAG_DO_NOT_WAIT, questa funzione blocca e esegue una sincronizzazione della CPU GPU per garantire che tutto il rendering sulla superficie accodata sia completato. Se questa funzione ha esito positivo, sarà disponibile una superficie per la rimozione dalla coda. Se si desidera un comportamento non di blocco, usare il flag DO_NOT_WAIT. Per informazioni dettagliate, vedere Flush().
  • In base alle regole di conteggio dei riferimenti COM, la superficie restituita da Dequeue sarà AddRef() in modo che l'applicazione non debba eseguire questa operazione. Dopo aver chiamato Accodamento, l'applicazione deve rilasciare la superficie perché non viene più usata.

Sciacquone

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

Parametri
Flag [in]
L'unico flag è SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Vedere la sezione Osservazioni. nSurfaces [out] Restituisce il numero di superfici ancora in sospeso e non scaricate.

Valori restituiti

Questa funzione può restituire DXGI_ERROR_WAS_STILL_DRAWING se viene usato il flag SURFACE_QUEUE_FLAG_DO_NOT_WAIT. Questa funzione restituisce S_OK se le superfici sono state scaricate correttamente. Questa funzione restituisce DXGI_ERROR_WAS_STILL_DRAWING solo se non sono state scaricate superfici. Insieme, il valore restituito e nSurfaces indicano all'applicazione il lavoro svolto e, se è stato lasciato un lavoro.

Osservazioni:

Flush è significativo solo se la chiamata precedente all'accodamento ha usato il flag di DO_NOT_WAIT; in caso contrario, sarà un no-op. Se la chiamata a accodamento ha usato il flag DO_NOT_WAIT, l'accodamento restituisce immediatamente e la sincronizzazione della CPU DELLA GPU non è garantita. La superficie è ancora considerata accodata, il dispositivo di produzione non può continuare a usarlo, ma non è disponibile per la rimozione dalla coda. Per provare a eseguire il commit della superficie per la rimozione dalla coda, è necessario chiamare Flush. Lo scaricamento tenta di eseguire il commit di tutte le superfici attualmente accodate. Se non viene passato alcun flag a Flush, verrà bloccato e cancellato l'intera coda, preparando tutte le superfici in esso contenute per la rimozione dalla coda. Se viene usato il flag DO_NOT_WAIT, la coda verificherà le superfici per verificare se uno di essi è pronto; questo passaggio non blocca. Le superfici che hanno completato la sincronizzazione GPU-CPU saranno pronte per il dispositivo consumer. Le superfici ancora in sospeso non saranno interessate. La funzione restituisce il numero di superfici che devono ancora essere scaricate.

Nota

Lo scaricamento non interromperà la semantica della coda. L'API garantisce che le superfici accodate vengano innanzitutto sottoposte a commit prima che le superfici vengano accodate in un secondo momento, indipendentemente dal momento in cui si verifica la sincronizzazione della CPU GPU.

 

Helper di interoperabilità Direct3D 9Ex e DXGI: Come usare

La maggior parte dei casi di utilizzo prevede la condivisione di una serie di superfici da parte di due dispositivi. Poiché questo è anche lo scenario più semplice, questo documento illustra in dettaglio come usare le API per raggiungere questo obiettivo, illustra una variante non bloccante e termina con una breve sezione sull'inizializzazione per tre dispositivi.

Due dispositivi

L'applicazione di esempio che usa questo helper può usare Insieme Direct3D 9Ex e Direct3D 11. L'applicazione può elaborare il contenuto con entrambi i dispositivi e presentare contenuto usando Direct3D 9. L'elaborazione può significare il rendering del contenuto, la decodifica di video, l'esecuzione di shader di calcolo e così via. Per ogni fotogramma, l'applicazione verrà prima elaborata con Direct3D 11, quindi elaborata con Direct3D 9 e infine presente con Direct3D 9. Inoltre, l'elaborazione con Direct3D 11 produrrà alcuni metadati che il Direct3D 9 presente dovrà utilizzare. Questa sezione illustra l'utilizzo dell'helper in tre parti che corrispondono a questa sequenza: Inizializzazione, Ciclo principale e Pulizia.

Inizializzazione
L'inizializzazione prevede i passaggi seguenti:

  1. Inizializzare entrambi i dispositivi.
  2. Creare la coda radice: m_11to9Queue.
  3. Clonare dalla coda radice: m_9to11Queue.
  4. Chiamare OpenProducer/OpenConsumer in entrambe le code.

I nomi delle code usano i numeri 9 e 11 per indicare quale API è il producer e qual è il consumer: m_producerallacoda consumer. Di conseguenza, m_11to9Queue indica una coda per cui il dispositivo Direct3D 11 produce superfici utilizzate dal dispositivo Direct3D 9. Analogamente, m_9to11Queue indica una coda per cui Direct3D 9 produce superfici utilizzate da Direct3D 11.
La coda radice è inizialmente piena e tutte le code clonate sono inizialmente vuote. Questo non deve essere un problema per l'applicazione, ad eccezione del primo ciclo di accodamento e dequeue e della disponibilità dei metadati. Se una coda richiede metadati ma nessuno è stato impostato (perché inizialmente non è presente nulla o l'accodamento non ha impostato alcun elemento), la coda non rileva che non sono stati ricevuti metadati.

  1. Inizializzare entrambi i dispositivi.

    m_pD3D9Device = InitializeD3D9ExDevice();
    m_pD3D11Device = InitializeD3D11Device();
    
  2. Creare la coda radice.
    Questo passaggio crea anche le superfici. Le restrizioni relative alle dimensioni e al formato sono identiche alla creazione di qualsiasi risorsa condivisa. Le dimensioni del buffer dei metadati sono fisse in fase di creazione e in questo caso passeremo semplicemente un UINT.
    La coda deve essere creata con un numero fisso di superfici. Le prestazioni variano a seconda dello scenario. La presenza di più superfici aumenta le probabilità che i dispositivi siano occupati. Ad esempio, se è presente una sola superficie, non vi sarà alcuna parallelizzazione tra i due dispositivi. D'altra parte, l'aumento del numero di superfici aumenta il footprint della memoria, che può ridurre le prestazioni. In questo esempio vengono utilizzate due superfici.

    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. Clonare la coda radice.
    Ogni coda clonata deve usare le stesse superfici, ma può avere dimensioni del buffer di metadati e flag diversi. In questo caso, non sono presenti metadati da Direct3D 9 a Direct3D 11.

    SURFACE_QUEUE_CLONE_DESC Desc;
    Desc.MetaDataSize = 0;
    Desc.Flags        = 0;
    
    m_11to9Queue->Clone(&Desc, &m_9to11Queue);
    
  4. Aprire producer e dispositivi consumer.
    L'applicazione deve eseguire questo passaggio prima di chiamare Accodamento e Dequeue. L'apertura di un producer e un consumer restituisce interfacce che contengono le API di accodamento/rimozione dalla coda.

    // 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);
    

Ciclo principale
L'utilizzo della coda viene modellato in base al problema classico producer/consumer. Si pensi a questo dal punto di vista per dispositivo. Ogni dispositivo deve eseguire questi passaggi: rimuovere dalla coda una superficie dalla coda di utilizzo, elaborare sulla superficie e quindi accodare nella coda di produzione. Per il dispositivo Direct3D 11, l'utilizzo di Direct3D 9 è quasi identico.

// 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);
}

Pulizia
Questo passaggio è molto semplice. Oltre ai normali passaggi per la pulizia delle API Direct3D, l'applicazione deve rilasciare le interfacce COM restituite.

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

Uso non bloccaggio

L'esempio precedente ha senso per un caso di utilizzo multithreading in cui ogni dispositivo ha un proprio thread. Nell'esempio vengono usate le versioni di blocco delle API: INFINITE per il timeout e nessun flag da accodare. Se si vuole usare l'helper in modo non bloccante, è necessario apportare solo alcune modifiche. Questa sezione illustra l'uso non bloccando con entrambi i dispositivi in un thread.

Inizializzazione
L'inizializzazione è identica ad eccezione dei flag. Poiché l'applicazione è a thread singolo, usare tale flag per la creazione. Questo disattiva parte del codice di sincronizzazione, che potenzialmente migliora le prestazioni.

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);

L'apertura dei dispositivi producer e consumer è identica a quella dell'esempio di blocco.
Uso della coda
Esistono molti modi per usare la coda in modo non bloccativo con diverse caratteristiche delle prestazioni. L'esempio seguente è semplice ma presenta prestazioni scarse a causa di un numero eccessivo di rotazioni e polling. Nonostante questi problemi, l'esempio mostra come usare l'helper. L'approccio consiste nel rimanere costantemente seduti in un ciclo e dequeue, processo, accodamento e scaricamento. Se uno dei passaggi ha esito negativo perché la risorsa non è disponibile, l'applicazione tenta semplicemente di nuovo il ciclo successivo.

// 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);
}

Una soluzione più complessa potrebbe controllare il valore restituito dall'accodamento e dallo scaricamento per determinare se lo scaricamento è necessario.

Tre dispositivi

L'estensione degli esempi precedenti per coprire più dispositivi è semplice. Il codice seguente esegue l'inizializzazione. Dopo aver creato gli oggetti Producer/Consumer, il codice da usare è lo stesso. In questo esempio sono presenti tre dispositivi e quindi tre code. Le superfici passano da Direct3D 9 a Direct3D 10 a 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);

Come accennato in precedenza, la clonazione funziona allo stesso modo, indipendentemente dalla coda clonata. Ad esempio, la seconda chiamata Clone potrebbe essere stata disattivata dall'oggetto 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);

Conclusione

È possibile creare soluzioni che usano l'interoperabilità per usare la potenza di più API DirectX. L'interoperabilità dell'API grafica Windows offre ora un common surface management runtime DXGI 1.1. Questo runtime abilita il supporto per la condivisione della superficie sincronizzata nelle API appena sviluppate, ad esempio Direct3D 11, Direct3D 10.1 e Direct2D. I miglioramenti dell'interoperabilità tra le nuove API e le API esistenti facilitano la migrazione delle applicazioni e la compatibilità con le versioni precedenti. Le API consumer Direct3D 9Ex e DXGI 1.1 possono interagire, come illustrato con il meccanismo di sincronizzazione disponibile nelle app di esempio Win32 precedenti disponibili nel repository di microsoft samples di MSDN Code Gallery archiviato.