Skip to main content
XG Memory est une bibliothèque d’exécution auxiliaire permettant de créer des mappages de mémoire spécialisés pour les titres du Microsoft Game Development Kit (GDK). Elle a été conçue pour succéder à plusieurs méthodes de mappage de l’ESRAM introduites avec l’API Direct3D 11.X de l’ancien système d’exploitation des titres. Pour Direct3D 12.X sur XBOX One, nous recommandons XG Memory pour accéder à la mémoire ESRAM haute vitesse. Cette vue d’ensemble décrit les composants de XG Memory et leur fonctionnement conjoint avec les API système de mappage de la mémoire. XG Memory est fournie sous forme de code source (entièrement inline) dans xgmemory.h et xgmemory.inl dans le Gaming eXtensions Development Kit (GXDK), afin de pouvoir être personnalisée si nécessaire.

Philosophie de conception

Fondamentalement, XG Memory est une solution permettant de mapper des pages de mémoire physique (pages système et pages ESRAM) vers une plage d’adresses virtuelles. Le système d’exploitation des titres et la pile de pilotes graphiques du Microsoft Game Development Kit (GDK) fournissent des API de bas niveau telles que XMemVirtualAlloc et XMemAllocatePhysicalPages pour effectuer ces opérations, mais elles peuvent être difficiles à utiliser efficacement. XG Memory est construite au-dessus de ces API de bas niveau et a été conçue selon les principes suivants.
  1. Fournir une API de haut niveau et facile à utiliser que tous les titres peuvent adopter pour le développement D3D12.X, voire D3D11.X. Parallèlement, livrer le code source afin que la complexité sous-jacente puisse être examinée et améliorée si nécessaire.
  2. Concevoir en tenant compte de la prise en charge des dispositions de mémoire dynamiques. Les titres modernes adoptent de plus en plus la résolution dynamique et d’autres techniques qui nécessitent de fréquents remappages des dispositions de mémoire au moment de l’exécution.
  3. Concevoir en tenant compte de la prise en charge d’un remappage facile de la mémoire au sein d’une même image. Une utilisation efficace de l’ESRAM nécessite des stratégies dans lesquelles différentes ressources peuvent partager les mêmes pages de mémoire si elles ne sont pas utilisées en même temps.
  4. Veiller à ce que l’aliasing de mémoire et l’aliasing de données entre les ressources soient mieux délimités pour faciliter l’outillage. L’aliasing de mémoire se produit lorsque deux ressources partagent la même mémoire, mais que les données qu’elle contient ne sont jamais vues simultanément par les deux ressources à des fins de réinterprétation. L’aliasing de données se produit lorsque deux ressources partagent la même mémoire avec l’intention de réinterpréter les données qu’elle contient de deux manières différentes.
Les anciennes API ESRAM de Direct3D 11.X traitaient toujours l’ESRAM comme un bloc de mémoire contigu, ce qui limitait fortement la flexibilité du partage de l’ESRAM entre deux ressources ou plus. Les anciennes API augmentaient également la complexité lorsqu’il fallait ajuster la consommation d’ESRAM d’une ressource. Les autres ressources devaient alors être corrigées pour s’adapter aux changements. XG Memory est conçue spécifiquement pour résoudre ces problèmes, car elle fonctionne sur des pages et non sur des plages. En outre, elle effectue les calculs à votre place pour allouer correctement les pages là où elles sont nécessaires.

Objets de l’API XG Memory

L’API XG Memory comporte trois objets d’API : le moteur, la disposition et le mappage.
  1. Le moteur (classe XGMemoryLayoutEngine) est un objet qui représente le budget mémoire que vous attribuez à une ou plusieurs dispositions de mémoire. Il stocke une liste de pages physiques d’ESRAM et/ou de mémoire système qui seront mappées vers les dispositions. C’est également là que les objets de disposition sont créés.
  2. La disposition (classe XGMemoryLayout) est un objet qui représente une disposition de mémoire unique, composée d’une plage d’adresses virtuelles réservée et de plusieurs mappages à l’intérieur de celle-ci. Bien que chaque moteur puisse créer autant de dispositions que vous le souhaitez, une seule disposition de chaque moteur doit être utilisée à un moment donné. Les dispositions d’un même moteur partagent les mêmes pages de mémoire physique.
  3. Le mappage (structure XGMemoryLayoutMapping) représente un mappage unique d’un ensemble de pages physiques vers une plage d’adresses virtuelles au sein d’une disposition. Une fois qu’un mappage est construit, une ou plusieurs ressources graphiques peuvent être créées par placement à l’adresse virtuelle du mappage.

Procédure pas à pas et exemples d’utilisation de XG Memory

Préparation à l’utilisation de XG Memory

Avant de commencer à utiliser XG Memory, réfléchissez à votre titre et à la place que XG Memory pourrait y occuper. Avez-vous seulement une ou deux ressources qui doivent utiliser l’ESRAM ? Avez-vous un sous-système entier qui doit réduire son empreinte mémoire grâce au partage ? Pouvez-vous configurer toutes les cibles de rendu de votre moteur au même endroit ? XG Memory devient plus utile à mesure que davantage de ressources sont placées dans la même disposition et que davantage d’opportunités de partage de mémoire apparaissent. La conception des dispositions de XG Memory convient également mieux aux moteurs dans lesquels les ressources de cibles de rendu sont configurées en série (sous forme d’une suite séquentielle d’étapes sur le même thread).

Étape 1 : créer un moteur de disposition XG Memory

Pour commencer, créez un moteur contenant la quantité maximale de mémoire physique que vous souhaitez utiliser pour toutes les ressources qui seront créées à l’aide de XG Memory. Par exemple, vous pouvez créer un moteur avec 32 Mo (512 pages) d’ESRAM et 64 Mo (1 024 pages) supplémentaires de mémoire système. Lors de la création du moteur, vous pouvez soit transmettre une liste préallouée de numéros de pages physiques provenant de XMemAllocatePhysicalPages, soit demander à XG Memory d’appeler XMemAllocatePhysicalPages à votre place. Les numéros de pages ESRAM peuvent être générés trivialement en utilisant les indices 0 à 511 pour désigner les 512 pages de 64 Ko qui composent l’intégralité de l’ESRAM.

Étape 2 : créer une disposition XG Memory

Ensuite, déterminez la taille virtuelle totale de toutes les ressources que vous prévoyez de configurer, y compris le partage (c’est-à-dire en comptant deux fois les chevauchements). Par exemple, nous pouvons créer une disposition avec 128 Mo d’espace d’adressage virtuel pour couvrir environ 10 cibles 1080p de 32 bpp, plus une petite marge. Ce nombre peut être surestimé avec très peu de pénalité, car la création d’une disposition se contente de réserver de l’espace d’adressage virtuel. La réservation d’espace d’adressage virtuel est très peu coûteuse, et vous disposez de centaines de Go d’espace d’adressage virtuel. La réservation d’adresses virtuelles s’effectue en appelant XMemVirtualAlloc avec MEM_RESERVE. En plus de réserver de l’espace d’adressage virtuel, la disposition contient des listes libres de pages de mémoire physique obtenues auprès du moteur. Lors de la création des mappages, les pages sont prélevées dans la liste libre selon le principe dernier entré, premier sorti (LIFO).

Étape 3 : créer des mappages et des ressources placées

Pour chaque ressource que vous souhaitez configurer, déterminez la taille de la ressource dans l’espace d’adressage virtuel à l’aide de la bibliothèque XG, puis arrondissez au supérieur et divisez pour obtenir un nombre de pages de 64 Ko. La classe de disposition XG Memory dispose de plusieurs méthodes de création de mappages, mais elles partagent toutes un concept commun. Pour chaque mappage, vous spécifiez un nombre de pages ESRAM et un nombre de pages de mémoire système à utiliser lors de la validation des pages physiques dans le mappage. Les différentes API de création de mappages ne diffèrent que par la complexité du modèle de mappage à générer (l’ordre spécifique des pages ESRAM et système dans le mappage). En interne, XG Memory utilise une combinaison de XMemMapPhysicalPages et de D3DMapEsramPages pour valider respectivement les pages système et ESRAM dans l’espace d’adressage virtuel réservé de la disposition. Une fois qu’un mappage est créé, vous pouvez utiliser le membre MappingBaseAddress de la structure XGMemoryLayoutMapping comme entrée d’une API de création de ressources placées, telle que ID3D12Device::CreatePlacedResourceX. N’oubliez pas que les adresses virtuelles graphiques sur XBOX One sont uniformes entre le processeur et le GPU ; vous pouvez donc convertir une valeur d’adresse UINT64 en void* ou inversement.

Étape 4 (facultative) : abandonner des mappages pour réutiliser des pages physiques

Si vous souhaitez partager des pages entre deux ressources ou plus, vous pouvez abandonner (relinquish) un mappage afin de remettre ses pages physiques dans la liste libre de la disposition. Notez que l’opération d’abandon ne libère pas la mémoire validée du mappage. Elle permet de réaffecter les pages validées pour ce mappage à de nouveaux mappages. Par conséquent, après avoir abandonné un mappage, vous ne pouvez plus utiliser la mémoire de ce mappage une fois que la mémoire associée aux mappages suivants est utilisée. L’abandon peut être considéré comme une barrière entre une utilisation de la mémoire et une autre utilisation de la même mémoire. L’abandon facilite également l’outillage et la déduction de l’intention, car la mémoire n’est réutilisée qu’au niveau physique, et non au niveau virtuel. Les deux mappages différents ont des adresses virtuelles uniques. Si vous souhaitez créer intentionnellement un alias de mémoire (par exemple, superposer une cible de couleur à un tampon de stencil pour remplir rapidement le stencil), vous devez le faire en créant deux ressources placées à l’aide de la même adresse virtuelle du même mappage.

Pseudocode de scénario

Considérez la séquence suivante de pseudo-appels d’API, en supposant qu’un moteur de disposition de mémoire a déjà été créé.
  1. CreateLayout(“Rendertargets”, WorstCaseTotalPageCount, &layout)
  2. CreateMapping(“Shadow Map”, &mapping1)
  3. Map(mapping1, ShadowMapPageCount, ShadowMapEsramPageCount)
  4. CreatePlacedResourceX(mapping1.address, ShadowMapDesc, &pShadowMapResource)
  5. CreateMapping(“Color Target”, &mapping2)
  6. Map(mapping2, ColorTargetPageCount, ColorTargetEsramPageCount)
  7. CreatePlacedResourceX(mapping2.address, ColorTargetDesc, &pColorTargetResource)
  8. RelinquishMapping(mapping1)
  9. CreateMapping(“Post Effects Target”, &mapping3)
  10. Map(mapping3, PostEffectsPageCount, PostEffectsEsramPageCount)
  11. CreatePlacedResourceX(mapping3.address, PostEffectsDesc, &pPostEffectsResource)
Cette séquence crée trois cibles de rendu : une carte d’ombres, une cible de couleur et une cible de post-effets. Grâce à la fonctionnalité d’abandon, la carte d’ombres et la cible de post-effets partagent la même mémoire. Notez que le titre n’effectue ici aucun calcul dépendant. Toutes les allocations sont calculées par la disposition à mesure que chaque mappage est créé dans l’ordre. Supposons maintenant que vous avez effectué un profilage et décidé que la répartition des pages ESRAM entre les ressources doit être mise à jour. La cible de couleur a besoin de plus d’ESRAM. Il suffit de réduire la valeur ShadowMapEsramPageCount et d’augmenter la valeur ColorTargetEsramPageCount. XG Memory s’occupe du reste : les pages ESRAM sont réallouées de manière flexible de la carte d’ombres et de la cible de post-effets vers la cible de couleur. Notez qu’à tout moment pendant la création de la disposition, vous pouvez obtenir le nombre actuel de pages ESRAM libres et de pages système libres. La même technique peut être utilisée si vous devez insérer une nouvelle cible de rendu dans la séquence. Par exemple, nous pouvons ajouter un quatrième mappage (une cible de profondeur) dans la disposition comme suit.
  1. CreateLayout(“Rendertargets”, WorstCaseTotalPageCount, &layout)
  2. CreateMapping(“Shadow Map”, &mapping1)
  3. Map(mapping1, ShadowMapPageCount, ShadowMapEsramPageCount)
  4. CreatePlacedResourceX(mapping1.address, ShadowMapDesc, &pShadowMapResource)
  5. CreateMapping(“Color Target”, &mapping2)
  6. Map(mapping2, ColorTargetPageCount, ColorTargetEsramPageCount)
  7. CreatePlacedResourceX(mapping2.address, ColorTargetDesc, &pColorTargetResource)
  8. CreateMapping(“Depth Target”, &mapping4)
  9. Map(mapping4, DepthTargetPageCount, DepthTargetEsramPageCount)
  10. CreatePlacedResourceX(mapping4.address, DepthTargetDesc, &pDepthTargetResource)
  11. RelinquishMapping(mapping1)
  12. CreateMapping(“Post Effects Target”, &mapping3)
  13. Map(mapping3, PostEffectsPageCount, PostEffectsEsramPageCount)
  14. CreatePlacedResourceX(mapping3.address, PostEffectsDesc, &pPostEffectsResource)
Notez qu’aucune modification n’a dû être apportée au code environnant. Lors de l’ajout d’un nouveau mappage, vous devrez peut-être rééquilibrer le nombre de pages ESRAM entre les autres mappages, mais vous n’avez jamais à vous soucier des plages contiguës, des chevauchements d’adresses virtuelles ou de tout autre calcul dépendant. Supposons ensuite que vous devez modifier dynamiquement la taille des cibles de rendu pour un changement de résolution dynamique. Cependant, vous avez déjà bien équilibré l’utilisation de l’ESRAM entre toutes les ressources et vous ne voulez pas avoir à retravailler cet équilibre. Ce n’est pas un problème avec XG Memory : il suffit d’ajuster les variables de nombre de pages (ShadowMapPageCount, ColorTargetPageCount, etc.). XG Memory s’occupe du reste, en conservant vos allocations ESRAM intactes. Il vous suffit de vous assurer que la valeur WorstCaseTotalPageCount est suffisamment grande pour gérer la configuration la plus volumineuse de toutes vos ressources.

Conclusion

XG Memory peut réduire considérablement la complexité de l’utilisation de l’ESRAM sur XBOX One. En outre, elle peut s’avérer utile même avec des dispositions de mémoire pour lesquelles la réutilisation des pages est souhaitable, mais qui sont composées à 100 % de pages système. Vos commentaires sur XG Memory sont les bienvenus via le Game Developer Support.

Voir aussi

d3d12_x
Last modified on October 6, 2026