Share via


Partage surface entre les API graphiques Windows

Cette rubrique fournit une vue d’ensemble technique de l’interopérabilité à l’aide du partage de surface entre les API graphiques Windows, notamment Direct3D 11, Direct2D, DirectWrite, Direct3D 10 et Direct3D 9Ex. Si vous avez déjà une connaissance pratique de ces API, ce document peut vous aider à utiliser plusieurs API pour effectuer un rendu sur la même surface dans une application conçue pour les systèmes d’exploitation Windows 7 ou Windows Vista. Cette rubrique fournit également des instructions sur les meilleures pratiques et des pointeurs vers des ressources supplémentaires.

Notes

Pour l’interopérabilité direct2D et DirectWrite sur le runtime DirectX 11.1, vous pouvez utiliser des appareils Direct2D et des contextes d’appareil pour effectuer un rendu direct sur des appareils Direct3D 11.

 

Cette rubrique contient les sections suivantes.

Introduction

Dans ce document, l’interopérabilité de l’API graphique Windows fait référence au partage de la même surface de rendu par différentes API. Ce type d’interopérabilité permet aux applications de créer des affichages attrayants en tirant parti de plusieurs API graphiques Windows et de faciliter la migration vers de nouvelles technologies en conservant la compatibilité avec les API existantes.

Dans Windows 7 (et Windows Vista SP2 avec Windows 7 Interop Pack, Vista 7IP), les API de rendu graphique sont Direct3D 11, Direct2D, Direct3D 10.1, Direct3D 10.1, Direct3D 10.0, Direct3D 9Ex, Direct3D 9c et versions antérieures, ainsi que GDI et GDI+. Le composant WIC (Windows Imaging Component) et les DirectWrite sont des technologies associées pour le traitement d’images, et Direct2D effectue le rendu du texte. L’API d’accélération vidéo DirectX (DXVA), basée sur Direct3D 9c et Direct3D 9Ex, est utilisée pour le traitement vidéo.

Alors que les API graphiques Windows évoluent pour devenir basées sur Direct3D, Microsoft investit plus d’efforts pour garantir l’interopérabilité entre les API. Les API Direct3D nouvellement développées et les API de niveau supérieur basées sur les API Direct3D fournissent également une prise en charge, si nécessaire, pour assurer la compatibilité avec les API plus anciennes. À titre d’exemple, les applications Direct2D peuvent utiliser Direct3D 10.1 en partageant un appareil Direct3D 10.1. En outre, les API Direct3D 11, Direct2D et Direct3D 10.1 peuvent toutes tirer parti de DirectX Graphics Infrastructure (DXGI) 1.1, qui permet des surfaces partagées synchronisées qui prennent entièrement en charge l’interopérabilité entre ces API. Les API basées sur DXGI 1.1 interagissent avec GDI et avec GDI+ par association, en obtenant le contexte d’appareil GDI à partir d’une surface DXGI 1.1. Pour plus d’informations, consultez la documentation sur l’interopérabilité DXGI et GDI disponible sur MSDN.

Le partage de surface non synchronisé est pris en charge par le runtime Direct3D 9Ex. Les applications vidéo basées sur DXVA peuvent utiliser l’assistance d’interopérabilité Direct3D 9Ex et DXGI pour l’interopérabilité DXVA basée sur Direct3D 9Ex avec Direct3D 11 pour le nuanceur de calcul, ou peuvent interagir avec Direct2D pour les contrôles 2D ou le rendu de texte. WIC et DirectWrite également interagir avec GDI, Direct2D et, par association, d’autres API Direct3D.

Les runtimes Direct3D 10.0, Direct3D 9c et les anciens runtimes Direct3D ne prennent pas en charge les surfaces partagées. Les copies de mémoire système continueront d’être utilisées pour l’interopérabilité avec les API GDI ou DXGI.

Notez que les scénarios d’interopérabilité dans ce document font référence à plusieurs API graphiques rendues sur une surface de rendu partagée, plutôt qu’à la même fenêtre d’application. La synchronisation pour des API distinctes ciblant différentes surfaces qui sont ensuite composites dans la même fenêtre n’entre pas dans le cadre de ce document.

Vue d’ensemble de l’interopérabilité des API

L’interopérabilité du partage surface des API graphiques Windows peut être décrite en termes de scénarios API à API et de la fonctionnalité d’interopérabilité correspondante. À partir de Windows 7 et à compter de Windows Vista SP2 avec 7IP, les nouvelles API et les runtimes associés incluent Direct2D et les technologies associées : Direct3D 11 et DXGI 1.1. Les performances GDI ont également été améliorées dans Windows 7. Direct3D 10.1 a été introduit dans Windows Vista SP1. Le diagramme suivant montre la prise en charge de l’interopérabilité entre les API.

diagramme de prise en charge de l’interopérabilité entre les API graphiques Windows

Dans ce diagramme, les flèches indiquent des scénarios d’interopérabilité dans lesquels la même surface peut être accessible par les API connectées. Les flèches bleues indiquent les mécanismes d’interopérabilité introduits dans Windows Vista. Les flèches vertes indiquent la prise en charge de l’interopérabilité pour les nouvelles API ou les améliorations qui aident les anciennes API à interagir avec les API plus récentes. Par exemple, les flèches vertes représentent le partage d’appareils, la prise en charge de surface partagée synchronisée, l’aide à la synchronisation Direct3D 9Ex/DXGI et l’obtention d’un contexte d’appareil GDI à partir d’une surface compatible.

Scénarios d’interopérabilité

Depuis Windows 7 et Windows Vista 7IP, les offres standard des API graphiques Windows prennent en charge le rendu de plusieurs API sur la même surface DXGI 1.1.

Direct3D 11, Direct3D 10.1, Direct2D — Interopérabilité entre eux

Les API Direct3D 11, Direct3D 10.1 et Direct2D (et ses API associées telles que DirectWrite et WIC) peuvent interagir entre elles à l’aide du partage d’appareils Direct3D 10.1 ou de surfaces partagées synchronisées.

Partage d’appareils Direct3D 10.1 avec Direct2D

Le partage d’appareils entre Direct2D et Direct3D 10.1 permet à une application d’utiliser les deux API pour effectuer un rendu transparent et efficace sur la même surface DXGI 1.1, en utilisant le même objet d’appareil Direct3D sous-jacent. Direct2D permet d’appeler des API Direct2D à l’aide d’un appareil Direct3D 10.1 existant, en tirant parti du fait que Direct2D est basé sur les runtimes Direct3D 10.1 et DXGI 1.1. Les extraits de code suivants illustrent comment Direct2D obtient la cible de rendu d’appareil Direct3D 10.1 à partir d’une surface DXGI 1.1 associée à l’appareil. La cible de rendu d’appareil Direct3D 10.1 peut exécuter des appels de dessin Direct2D entre les API BeginDraw et 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);

Remarques

  • L’appareil Direct3D 10.1 associé doit prendre en charge le format BGRA. Cet appareil a été créé en appelant D3D10CreateDevice1 avec le paramètre D3D10_CREATE_DEVICE_BGRA_SUPPORT. Le format BGRA est pris en charge à partir du niveau de fonctionnalité Direct3D 10 9.1.
  • L’application ne doit pas créer plusieurs ID2D1RenderTargets associés au même appareil Direct3D10.1.
  • Pour des performances optimales, conservez au moins une ressource à tout moment, comme les textures ou les surfaces associées à l’appareil.

Le partage d’appareils convient à l’utilisation in-process et monothread d’un appareil de rendu partagé par les API de rendu Direct3D 10.1 et Direct2D. Les surfaces partagées synchronisées permettent l’utilisation multithread, en cours et hors processus de plusieurs appareils de rendu utilisés par les API Direct3D 10.1, Direct2D et Direct3D 11.

Une autre méthode d’interopérabilité Direct3D 10.1 et Direct2D consiste à utiliser ID3D1RenderTarget::CreateSharedBitmap, qui crée un objet ID2D1Bitmap à partir d’IDXGISurface. Vous pouvez écrire une scène Direct3D10.1 dans la bitmap et la restituer avec Direct2D. Pour plus d’informations, consultez ID2D1RenderTarget::CreateSharedBitmap, méthode.

Rastérisation logicielle Direct2D

Le partage d’appareils avec Direct3D 10.1 n’est pas pris en charge lors de l’utilisation du convertisseur logiciel Direct2D, par exemple, en spécifiant D2D1_RENDER_TARGET_USAGE_FORCE_SOFTWARE_RENDERING dans D2D1_RENDER_TARGET_USAGE lors de la création d’une cible de rendu Direct2D.

Direct2D peut utiliser le rastériseur logiciel WARP10 pour partager un appareil avec Direct3D 10 ou Direct3D 11, mais les performances diminuent considérablement.

Surfaces partagées synchronisées DXGI 1.1

Les API Direct3D 11, Direct3D 10.1 et Direct2D utilisent toutes DXGI 1.1, qui fournit la fonctionnalité permettant de synchroniser la lecture et l’écriture à partir de la même surface de mémoire vidéo (DXGISurface1) par deux ou plusieurs appareils Direct3D. Les appareils de rendu utilisant des surfaces partagées synchronisées peuvent être des appareils Direct3D 10.1 ou Direct3D 11, chacun s’exécutant dans le même processus ou inter-processus.

Les applications peuvent utiliser des surfaces partagées synchronisées pour interagir entre des appareils DXGI 1.1, tels que Direct3D 11 et Direct3D 10.1, ou entre Direct3D 11 et Direct2D, en obtenant l’appareil Direct3D 10.1 à partir de l’objet cible de rendu Direct2D.

Dans les API Direct3D 10.1 et ultérieures, pour utiliser DXGI 1.1, vérifiez que l’appareil Direct3D est créé à l’aide d’un objet adaptateur DXGI 1.1, énuméré à partir de l’objet de fabrique DXGI 1.1. Appelez CreateDXGIFactory1 pour créer l’objet IDXGIFactory1 et EnumAdapters1 pour énumérer l’objet IDXGIAdapter1. L’objet IDXGIAdapter1 doit être transmis dans le cadre de l’appel D3D10CreateDevice ou D3D10CreateDeviceAndSwapChain. Pour plus d’informations sur les API DXGI 1.1, consultez le Guide de programmation pour DXGI.

API

D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX
Lors de la création de la ressource partagée synchronisée, définissez D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX dans 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
Permet de synchroniser la ressource créée à l’aide des API IDXGIKeyedMutex::AcquireSync et ReleaseSync. Les API Direct3D 10.1 de création de ressources suivantes qui prennent toutes un paramètre D3D10_RESOURCE_MISC_FLAG ont été étendues pour prendre en charge le nouvel indicateur.

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

Si l’une des fonctions répertoriées est appelée avec le jeu d’indicateurs D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX, l’interface retournée peut être interrogée pour une interface IDXGIKeyedMutex, qui implémente les API AcquireSync et ReleaseSync pour synchroniser l’accès à la surface. L’appareil qui crée la surface et tout autre appareil ouvrant la surface (à l’aide d’OpenSharedResource) doit appeler IDXGIKeyedMutex::AcquireSync avant toute commande de rendu sur la surface, et IDXGIKeyedMutex::ReleaseSync quand le rendu est terminé.
Les appareils WARP et REF ne prennent pas en charge les ressources partagées. Si vous tentez de créer une ressource avec cet indicateur sur un appareil WARP ou REF, la méthode create retourne un code d’erreur E_OUTOFMEMORY.
IDXGIKEYEDMUTEX INTERFACE
Une nouvelle interface dans DXGI 1.1, IDXGIKeyedMutex, représente un mutex à clé, qui permet un accès exclusif à une ressource partagée utilisée par plusieurs appareils. Pour obtenir de la documentation de référence sur cette interface et ses deux méthodes, AcquireSync et ReleaseSync, consultez IDXGIKeyedMutex.

Exemple : Partage surface synchronisé entre deux appareils Direct3D 10.1

L’exemple ci-dessous illustre le partage d’une surface entre deux appareils Direct3D 10.1. La surface partagée synchronisée est créée par un appareil 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;

Le même appareil Direct3D10.1 peut obtenir la surface partagée synchronisée pour le rendu en appelant AcquireSync, puis en libérant la surface pour le rendu de l’autre appareil en appelant ReleaseSync. Lorsqu’il ne partage pas la surface partagée synchronisée avec un autre appareil Direct3D, le créateur peut obtenir et libérer la surface partagée synchronisée (pour démarrer et terminer le rendu) en acquérant et en utilisant la même valeur de clé.

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

Le deuxième appareil Direct3D10.1 peut obtenir la surface partagée synchronisée pour le rendu en appelant AcquireSync, puis en libérant la surface pour le rendu du premier appareil en appelant ReleaseSync. Notez que l’appareil 2 peut acquérir la surface partagée synchronisée à l’aide de la même valeur de clé que celle spécifiée dans l’appel ReleaseSync par l’appareil 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;

Les appareils supplémentaires partageant la même surface peuvent se relayer pour acquérir et libérer la surface à l’aide de clés supplémentaires, comme illustré dans les appels suivants.

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

Notez qu’une application réelle peut toujours s’afficher sur une surface intermédiaire qui est ensuite copiée dans la surface partagée pour éviter qu’un appareil n’attende sur un autre appareil qui partage la surface.

Utilisation de surfaces partagées synchronisées avec Direct2D et Direct3D 11

De même, pour le partage entre direct3D 11 et les API Direct3D 10.1, une surface partagée synchronisée peut être créée à partir d’un appareil d’API et partagée avec les autres appareils d’API, en cours ou hors processus.

Les applications qui utilisent Direct2D peuvent partager un appareil Direct3D 10.1 et utiliser une surface partagée synchronisée pour interagir avec Direct3D 11 ou d’autres appareils Direct3D 10.1, qu’ils appartiennent au même processus ou à des processus différents. Toutefois, pour les applications monoprocesseurs et à thread unique, le partage d’appareils est la méthode d’interopérabilité la plus performante et la plus efficace entre Direct2D et Direct3D 10 ou Direct3D 11.

Rastériseur logiciel

Les surfaces partagées synchronisées ne sont pas prises en charge lorsque les applications utilisent les rastériseurs logiciels Direct3D ou Direct2D, y compris le rastériseur de référence et WARP, au lieu d’utiliser l’accélération matérielle graphique.

Interopérabilité entre les API Direct3D 9Ex et DXGI

Les API Direct3D 9Ex incluaient la notion de partage de surface pour permettre à d’autres API de lire à partir de la surface partagée. Pour partager la lecture et l’écriture sur une surface partagée Direct3D 9Ex, vous devez ajouter la synchronisation manuelle à l’application elle-même.

Surfaces partagées Direct3D 9Ex Plus Aide à la synchronisation manuelle

La tâche la plus fondamentale dans l’interopérabilité Direct3D 9Ex et Direct3D 10 ou 11 consiste à passer une surface unique du premier appareil (appareil A) au second (appareil B), de sorte que lorsque l’appareil B acquiert un handle sur la surface, le rendu de l’appareil A est garanti. Par conséquent, l’appareil B peut utiliser cette surface sans souci. C’est très similaire au problème classique producteur-consommateur et cette discussion modélise le problème de cette façon. Le premier appareil qui utilise la surface, puis abandonne, il s’agit du producteur (appareil A), et l’appareil qui attend initialement est le consommateur (appareil B). Toute application réelle est plus sophistiquée que celle-ci et va chaîner plusieurs blocs de construction producteur-consommateur pour créer la fonctionnalité souhaitée.

Les blocs de construction producteur-consommateur sont implémentés dans l’assistance à l’aide d’une file d’attente de surfaces. Les surfaces sont mises en file d’attente par le producteur et mises en file d’attente par le consommateur. L’assistance introduit trois interfaces COM : ISurfaceQueue, ISurfaceProducer et ISurfaceConsumer.

High-Level vue d’ensemble de l’assistance

L’objet ISurfaceQueue est le bloc de construction pour l’utilisation des surfaces partagées. Il est créé avec un appareil Direct3D initialisé et une description pour créer un nombre fixe de surfaces partagées. L’objet file d’attente gère la création de ressources et l’ouverture du code. Le nombre et le type de surfaces sont fixes ; une fois les surfaces créées, l’application ne peut pas les ajouter ou les supprimer.

Chaque instance de l’objet ISurfaceQueue fournit une sorte de rue unidirectionnel qui peut être utilisée pour envoyer des surfaces de l’appareil producteur à l’appareil consommateur. Plusieurs rues unidirectionnelles peuvent être utilisées pour activer des scénarios de partage de surface entre des appareils d’applications spécifiques.

Création/Durée de vie de l’objet
Il existe deux façons de créer l’objet file d’attente : via CreateSurfaceQueue ou par le biais de la méthode Clone de ISurfaceQueue. Étant donné que les interfaces sont des objets COM, la gestion de la durée de vie COM standard s’applique.
Modèle producteur/consommateur
Enqueue () : le producteur appelle cette fonction pour indiquer qu’elle est terminée avec la surface, qui peut désormais être disponible pour un autre appareil. Au retour de cette fonction, l’appareil producteur n’a plus de droits sur la surface et il est dangereux de continuer à l’utiliser.
Dequeue () : l’appareil consommateur appelle cette fonction pour obtenir une surface partagée. L’API garantit que toutes les surfaces en file d’attente sont prêtes à être utilisées.
Métadonnées
L’API prend en charge l’association de métadonnées aux surfaces partagées.
Enqueue() a la possibilité de spécifier des métadonnées supplémentaires qui seront transmises à l’appareil consommateur. Les métadonnées doivent être inférieures à un maximum connu au moment de la création.
Dequeue() peut éventuellement passer une mémoire tampon et un pointeur vers la taille de la mémoire tampon. La file d’attente remplit la mémoire tampon avec les métadonnées de l’appel Enqueue correspondant.
clonage
Chaque objet ISurfaceQueue résout une synchronisation unidirectionnelle. Nous partons du principe que la grande majorité des applications utilisant cette API utiliseront un système fermé. Le système fermé le plus simple avec deux appareils qui envoient des surfaces d’aller-retour nécessite deux files d’attente. L’objet ISurfaceQueue a une méthode Clone() pour permettre de créer plusieurs files d’attente qui font toutes partie du même pipeline plus grand.
Clone crée un objet ISurfaceQueue à partir d’un objet existant et partage toutes les ressources ouvertes entre eux. L’objet résultant a exactement les mêmes surfaces que la file d’attente source. Les files d’attente clonées peuvent avoir des tailles de métadonnées différentes les unes des autres.
Surfaces
ISurfaceQueue est responsable de la création et de la gestion de ses surfaces. Il n’est pas valide de mettre en file d’attente des surfaces arbitraires. En outre, une surface ne doit avoir qu’un seul « propriétaire » actif. Il doit se trouver dans une file d’attente spécifique ou être utilisé par un appareil spécifique. Il n’est pas valide de l’avoir dans plusieurs files d’attente ou pour les appareils de continuer à utiliser la surface après sa file d’attente.

Détails de l’API

IsurfaceQueue

La file d’attente est responsable de la création et de la maintenance des ressources partagées. Il fournit également la fonctionnalité permettant de chaîner plusieurs files d’attente à l’aide de Clone. La file d’attente a des méthodes qui ouvrent l’appareil de production et un appareil consommateur. Un seul de chaque peut être ouvert à tout moment.

La file d’attente expose les API suivantes :

API Description
CreateSurfaceQueue Crée un objet ISurfaceQueue (la file d’attente « racine »).
ISurfaceQueue::OpenConsumer Retourne une interface pour que l’appareil consommateur se désexécute.
ISurfaceQueue::OpenProducer Retourne une interface pour que l’appareil de production soit en file d’attente.
ISurfaceQueue::Clone Crée un objet ISurfaceQueue qui partage des surfaces avec l’objet de file d’attente racine.

 

CreateSurfaceQueue

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

Members (Membres)

Largeur, Hauteur Dimensions des surfaces partagées. Toutes les surfaces partagées doivent avoir les mêmes dimensions.
Format Format des surfaces partagées. Toutes les surfaces partagées doivent avoir le même format. Les formats valides dépendent des appareils qui seront utilisés, car différentes paires d’appareils peuvent partager différents types de format.
NumSurfaces Nombre de surfaces qui font partie de la file d’attente. Il s’agit d’un nombre fixe.
MetaDataSize Taille maximale de la mémoire tampon de métadonnées.
Drapeaux Indicateurs pour contrôler le comportement de la file d’attente. Consultez la section Notes.

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

Paramètres

pDesc [in] Description de la file d’attente de surface partagée à créer.

pDevice [in] Appareil qui doit être utilisé pour créer les surfaces partagées. Il s’agit d’un paramètre explicite en raison d’une fonctionnalité dans Windows Vista. Pour les surfaces partagées entre Direct3D 9 et Direct3D 10, les surfaces doivent être créées avec Direct3D 9.

ppQueue [out] Au retour, contient un pointeur vers l’objet ISurfaceQueue.

Valeurs retournées

Si pDevice n’est pas capable de partager des ressources, cette fonction retourne DXGI_ERROR_INVALID_CALL. Cette fonction crée les ressources. En cas d’échec, il retourne une erreur. Si elle réussit, elle retourne S_OK.

Remarques

La création de l’objet file d’attente crée également toutes les surfaces. Toutes les surfaces sont supposées être des cibles de rendu 2D et seront créées avec les indicateurs D3D10_BIND_RENDER_TARGET et D3D10_BIND_SHADER_RESOURCE définis (ou les indicateurs équivalents pour les différents runtimes).

Le développeur peut spécifier un indicateur qui indique si la file d’attente sera accessible par plusieurs threads. Si aucun indicateur n’est défini (Indicateurs == 0), la file d’attente est utilisée par plusieurs threads. Le développeur peut spécifier l’accès à thread unique, ce qui désactive le code de synchronisation et améliore les performances dans ces cas. Chaque file d’attente cloné a son propre indicateur. Il est donc possible pour différentes files d’attente dans le système d’avoir des contrôles de synchronisation différents.

Ouvrir un producteur

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

Paramètres

pDevice [in]

L’appareil producteur qui met la file d’attente de surface dans la file d’attente de surface.

ppProducer [out] Renvoie un objet à l’interface de producteur.

Valeurs retournées

Si l’appareil ne peut pas partager des surfaces, retourne DXGI_ERROR_INVALID_CALL.

Ouvrir un consommateur

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

Paramètres
pDevice [in]
L’appareil grand public qui fait la file d’attente de la surface. ppConsumer [out] Renvoie un objet à l’interface consommateur.

Valeurs retournées

Si l’appareil ne peut pas partager des surfaces, retourne DXGI_ERROR_INVALID_CALL.

Remarques

Cette fonction ouvre toutes les surfaces de la file d’attente pour le périphérique d’entrée et les met en cache. Les appels suivants à Dequeue vont simplement dans le cache et n’ont pas besoin de rouvrir les surfaces à chaque fois.

Clonage d’un IDXGIXSurfaceQueue

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

Les membresMetaDataSize et Flags ont le même comportement que pour CreateSurfaceQueue.

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

Paramètres

pDesc [in] struct qui fournit une description de l’objet Clone à créer. Ce paramètre doit être initialisé.
ppQueue [out] Renvoie l’objet initialisé.

Remarques

Vous pouvez cloner à partir de n’importe quel objet de file d’attente existant, même s’il ne s’agit pas de la racine.

IDXGIXSurfaceConsumer

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

Paramètres
id [in]
REFIID d’une surface 2D de l’appareil consommateur.

  • Pour un IDirect3DDevice9, le REFIID doit être __uuidof(IDirect3DTexture9).
  • Pour un ID3D10Device, le REFIID doit être __uuidof(ID3D10Texture2D).
  • Pour un ID3D11Device, le REFIID doit être __uuidof(ID3D11Texture2D).

ppSurface [out] Renvoie un pointeur vers la surface.
pBuffer [in, out] Paramètre facultatif et, s’il n’est pas NULL, au retour, contient les métadonnées qui ont été transmises à l’appel en file d’attente correspondant.
pBufferSize [in, out] Taille de pBuffer, en octets. Retourne le nombre d’octets retournés dans pBuffer. Si l’appel en file d’attente n’a pas fourni de métadonnées, pBuffer est défini sur 0.
dwTimeout [in] Spécifie une valeur de délai d’expiration. Pour plus d’informations, consultez les remarques.

Valeurs retournées

Cette fonction peut retourner WAIT_TIMEOUT si une valeur de délai d’expiration est spécifiée et si la fonction ne retourne pas avant la valeur de délai d’expiration. Consultez la section Notes. Si aucune surface n’est disponible, la fonction retourne avec ppSurface défini sur NULL, pBufferSize défini sur 0 et la valeur de retour est 0x80070120 (WIN32_TO_HRESULT(WAIT_TIMEOUT)).

Remarques

Cette API peut bloquer si la file d’attente est vide. Le paramètre dwTimeout fonctionne de manière identique aux API de synchronisation Windows, telles que WaitForSingleObject. Pour un comportement non bloquant, utilisez un délai d’expiration de 0.

ISurfaceProducer

Cette interface fournit deux méthodes qui permettent à l’application de mettre en file d’attente des surfaces. Une fois qu’une surface est en file d’attente, le pointeur de surface n’est plus valide et n’est pas sûr à utiliser. La seule action que l’application doit effectuer avec le pointeur consiste à le libérer.

Méthode Description
ISurfaceProducer::Enqueue Met en file d’attente une surface à l’objet file d’attente. Une fois cet appel terminé, le producteur est terminé avec la surface et la surface est prête pour un autre appareil.
ISurfaceProducer::Flush Utilisé si les applications doivent avoir un comportement non bloquant. Pour plus de détails, consultez la section Notes.

 

Enqueue (empiler)

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

Paramètres
pSurface [in]
Surface de l’appareil de production à mettre en file d’attente. Cette surface doit être une surface de file d’attente supprimée du même réseau de file d’attente. pBuffer [in] Paramètre facultatif, qui est utilisé pour transmettre les métadonnées. Il doit pointer vers les données qui seront transmises à l’appel de file d’attente.
BufferSize [in] Taille de pBuffer, en octets.
Indicateurs [in] Paramètre facultatif qui contrôle le comportement de cette fonction. Le seul indicateur est SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Consultez les remarques relatives à Flush. Si aucun indicateur n’est transmis (Indicateurs == 0), le comportement de blocage par défaut est utilisé.

Valeurs retournées

Cette fonction peut retourner DXGI_ERROR_WAS_STILL_DRAWING si un indicateur de SURFACE_QUEUE_FLAG_DO_NOT_WAIT est utilisé.

Remarques

  • Cette fonction place la surface sur la file d’attente. Si l’application ne spécifie pas SURFACE_QUEUE_FLAG_DO_NOT_WAIT, cette fonction est bloquée et effectue une synchronisation GPU-PROCESSEUR pour s’assurer que tout le rendu sur la surface en file d’attente est terminé. Si cette fonction réussit, une surface sera disponible pour la mise en file d’attente. Si vous souhaitez un comportement non bloquant, utilisez l’indicateur DO_NOT_WAIT. Pour plus d’informations, consultez Flush().
  • Conformément aux règles de comptage des références COM, la surface renvoyée par Dequeue sera AddRef() et l’application n’a donc pas besoin de le faire. Après avoir appelé Enqueue, l’application doit libérer la surface, car elle ne l’utilise plus.

Purge

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

Paramètres
Indicateurs [in]
Le seul indicateur est SURFACE_QUEUE_FLAG_ DO_NOT_WAIT. Consultez la section Notes. nSurfaces [out] Retourne le nombre de surfaces toujours en attente et non vidées.

Valeurs retournées

Cette fonction peut retourner DXGI_ERROR_WAS_STILL_DRAWING si l’indicateur SURFACE_QUEUE_FLAG_DO_NOT_WAIT est utilisé. Cette fonction retourne S_OK si des surfaces ont été correctement vidées. Cette fonction retourne DXGI_ERROR_WAS_STILL_DRAWING uniquement si aucune surface n’a été vidée. Ensemble, la valeur de retour et les nSurfaces indiquent à l’application quel travail a été effectué et s’il reste du travail à effectuer.

Remarques

Le vidage n’est significatif que si l’appel précédent à la file d’attente utilisait l’indicateur DO_NOT_WAIT ; sinon, ce sera un non-op. Si l’appel à enqueue utilisait l’indicateur DO_NOT_WAIT, la file d’attente retourne immédiatement et la synchronisation GPU-PROCESSEUR n’est pas garantie. La surface est toujours considérée comme en file d’attente, l’appareil de production ne peut pas continuer à l’utiliser, mais il n’est pas disponible pour la file d’attente. Pour essayer de valider la surface pour la mise en file d’attente, le vidage doit être appelé. Vidage tente de valider toutes les surfaces actuellement en file d’attente. Si aucun indicateur n’est passé à Flush, il bloquera et effacera toute la file d’attente, ce qui préparera toutes les surfaces qu’elle contient pour la mise en file d’attente. Si l’indicateur DO_NOT_WAIT est utilisé, la file d’attente case activée les surfaces pour voir si l’une d’elles est prête; cette étape n’est pas bloquante. Les Surfaces qui ont terminé la synchronisation GPU-PROCESSEUR seront prêtes pour l’appareil grand public. Les surfaces toujours en attente ne seront pas affectées. La fonction retourne le nombre de surfaces qui doivent encore être vidées.

Notes

Le vidage n’interrompt pas la sémantique de la file d’attente. L’API garantit que les surfaces en file d’attente seront validées en premier avant d’être mises en file d’attente ultérieurement, quel que soit le moment où la synchronisation GPU-PROCESSEUR se produit.

 

Direct3D 9Ex et DXGI Interop Helper : comment utiliser

Nous nous attendons à ce que la plupart des cas d’utilisation impliquent deux appareils partageant un certain nombre de surfaces. Étant donné qu’il s’agit également du scénario le plus simple, ce document explique comment utiliser les API pour atteindre cet objectif, traite d’une variation non bloquante et se termine par une brève section sur l’initialisation pour trois appareils.

Deux appareils

L’exemple d’application qui utilise cette assistance peut utiliser Direct3D 9Ex et Direct3D 11 ensemble. L’application peut traiter du contenu avec les deux appareils et présenter du contenu à l’aide de Direct3D 9. Le traitement peut signifier le rendu du contenu, le décodage de vidéos, l’exécution de nuanceurs de calcul, etc. Pour chaque image, l’application traite d’abord avec Direct3D 11, puis traite avec Direct3D 9 et enfin présente avec Direct3D 9. En outre, le traitement avec Direct3D 11 produira certaines métadonnées que le Direct3D 9 présent devra consommer. Cette section décrit l’utilisation de l’assistance en trois parties qui correspondent à cette séquence : Initialisation, Boucle principale et Nettoyage.

Initialisation
L’initialisation implique les étapes suivantes :

  1. Initialisez les deux appareils.
  2. Créez la file d’attente racine : m_11to9Queue.
  3. Clonez à partir de la file d’attente racine : m_9to11Queue.
  4. Appelez OpenProducer/OpenConsumer sur les deux files d’attente.

Les noms de file d’attente utilisent les numéros 9 et 11 pour indiquer quelle API est le producteur et quel est le consommateur : m_produiseurà la file d’attentedu consommateur. Par conséquent, m_11to9Queue indique une file d’attente pour laquelle l’appareil Direct3D 11 produit des surfaces consommées par l’appareil Direct3D 9. De même, m_9to11Queue indique une file d’attente pour laquelle Direct3D 9 produit des surfaces consommées par Direct3D 11.
La file d’attente racine est initialement pleine et toutes les files d’attente clonées sont initialement vides. Cela ne doit pas poser de problème pour l’application, sauf pour le premier cycle des enqueues et des dequeues et la disponibilité des métadonnées. Si un dequeue demande des métadonnées mais qu’aucune n’a été définie (soit parce qu’il n’y a rien à l’origine ou que la file d’attente n’a rien défini), dequeue constate qu’aucune métadonnées n’a été reçue.

  1. Initialisez les deux appareils.

    m_pD3D9Device = InitializeD3D9ExDevice();
    m_pD3D11Device = InitializeD3D11Device();
    
  2. Créez la file d’attente racine.
    Cette étape crée également les surfaces. Les restrictions de taille et de format sont identiques à la création d’une ressource partagée. La taille de la mémoire tampon de métadonnées est fixe au moment de la création, et dans ce cas, nous allons simplement passer un UINT.
    La file d’attente doit être créée avec un nombre fixe de surfaces. Les performances varient en fonction du scénario. Le fait d’avoir plusieurs surfaces augmente les risques que les appareils soient occupés. Par exemple, s’il n’y a qu’une seule surface, il n’y aura aucune parallélisation entre les deux appareils. D’autre part, l’augmentation du nombre de surfaces augmente l’encombrement de la mémoire, ce qui peut dégrader les performances. Cet exemple utilise deux surfaces.

    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. Clonez la file d’attente racine.
    Chaque file d’attente clonée doit utiliser les mêmes surfaces, mais peut avoir des tailles de mémoire tampon de métadonnées et des indicateurs différents. Dans ce cas, il n’existe aucune métadonnées de Direct3D 9 vers Direct3D 11.

    SURFACE_QUEUE_CLONE_DESC Desc;
    Desc.MetaDataSize = 0;
    Desc.Flags        = 0;
    
    m_11to9Queue->Clone(&Desc, &m_9to11Queue);
    
  4. Ouvrez les appareils producteur et grand public.
    L’application doit effectuer cette étape avant d’appeler Enqueue et Dequeue. L’ouverture d’un producteur et d’un consommateur retourne des interfaces qui contiennent les API d’enqueue/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);
    

Boucle principale
L’utilisation de la file d’attente est modélisée d’après le problème classique du producteur/consommateur. Pensez-y du point de vue de chaque appareil. Chaque appareil doit effectuer les étapes suivantes : mettre la file d’attente pour obtenir une surface à partir de sa file d’attente consommatrice, traiter sur la surface, puis mettre la file d’attente dans sa file d’attente de production. Pour l’appareil Direct3D 11, l’utilisation de Direct3D 9 est presque identique.

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

Nettoyage
Cette étape est très simple. En plus des étapes normales de nettoyage des API Direct3D, l’application doit libérer les interfaces COM de retour.

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

Utilisation non bloquante

L’exemple précédent est logique pour un cas d’utilisation multithread dans lequel chaque appareil a son propre thread. L’exemple utilise les versions bloquantes des API : INFINITE pour le délai d’attente et aucun indicateur à mettre en file d’attente. Si vous souhaitez utiliser l’assistance de manière non bloquante, vous ne devez apporter que quelques modifications. Cette section montre l’utilisation non bloquante avec les deux appareils sur un seul thread.

Initialisation
L’initialisation est identique, à l’exception des indicateurs. Étant donné que l’application est monothread, utilisez cet indicateur pour la création. Cela désactive une partie du code de synchronisation, ce qui améliore potentiellement les performances.

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’ouverture des appareils producteur et consommateur est la même que dans l’exemple de blocage.
Utilisation de la file d’attente
Il existe de nombreuses façons d’utiliser la file d’attente de manière non bloquante avec différentes caractéristiques de performances. L’exemple suivant est simple, mais présente des performances médiocres en raison d’une rotation et d’une interrogation excessives. Malgré ces problèmes, l’exemple montre comment utiliser l’assistance. L’approche consiste à s’asseoir constamment dans une boucle et à effectuer une file d’attente, à traiter, à mettre en file d’attente et à vider. Si l’une des étapes échoue parce que la ressource n’est pas disponible, l’application tente simplement de nouveau la boucle suivante.

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

Une solution plus complexe pourrait case activée la valeur de retour de la file d’attente et de la vidage pour déterminer si le vidage est nécessaire.

Trois appareils

L’extension des exemples précédents pour couvrir plusieurs appareils est simple. Le code suivant effectue l’initialisation. Une fois les objets Producteur/Consommateur créés, le code pour les utiliser est le même. Cet exemple comporte trois appareils et donc trois files d’attente. Les surfaces passent de Direct3D 9 à Direct3D 10 vers 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);

Comme mentionné précédemment, le clonage fonctionne de la même façon, quelle que soit la file d’attente cloné. Par exemple, le deuxième appel de clone aurait pu être désactivé de l’objet 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);

Conclusion

Vous pouvez créer des solutions qui utilisent l’interopérabilité pour utiliser la puissance de plusieurs API DirectX. L’interopérabilité de l’API graphique Windows offre désormais un runtime de gestion de surface commun DXGI 1.1. Ce runtime permet la prise en charge du partage de surface synchronisé dans les API nouvellement développées, telles que Direct3D 11, Direct3D 10.1 et Direct2D. Les améliorations de l’interopérabilité entre les nouvelles API et les API existantes facilitent la migration des applications et la compatibilité descendante. Les API grand public Direct3D 9Ex et DXGI 1.1 peuvent interagir, comme indiqué avec le mécanisme de synchronisation fourni via un exemple de code d’assistance sur MSDN Code Gallery.