Introduction
Le système de mémoire virtuelle graphique a été reconstruit pour le Microsoft Game Development Kit (GDK). Bien que les mécanismes internes soient entièrement nouveaux, l’ensemble des fonctionnalités n’est pas très différent de celui du système d’exploitation ERA de la XBOX One. Ces fonctionnalités incluent :- Un espace d’adressage virtuel CPU et GPU unifié pour la mémoire graphique, occupant les 1 024 Go inférieurs de l’espace d’adressage virtuel, les 4 Go inférieurs étant réservés aux allocations graphiques spécifiques nécessitant des adresses 32 bits.
- Une taille de page native de 64 Ko pour les graphiques, ainsi qu’une taille de page plus grande de 2 Mo.
- Les attributs graphiques spécifiés au moment de l’allocation de mémoire incluent la lecture/écriture, l’exécution et la cohérence du cache GPU.
- XMemAlloc, un tas en mode utilisateur souple et rapide pour la mémoire graphique, y compris la possibilité d’intercepter les allocations provenant de diverses bibliothèques de titres XBOX.
- Des API d’allocation et de mappage de pages physiques accessibles aux titres.
- Un accès direct du GPU aux mappages de pages GPU via les ressources en mosaïque de Direct3D 12 et les API d’extension de mappage de pages.
- Une taille d’allocation de la mémoire des tables de pages GPU contrôlable par le titre, allouée au moment de l’initialisation (aucune allocation à l’exécution).
Initialisation du système de mémoire graphique
Avant d’allouer de la mémoire graphique, le titre doit initialiser le système de mémoire graphique dans le noyau. Il s’agit d’une nouvelle exigence du Microsoft Game Development Kit (GDK). La façon la plus simple d’initialiser le système de mémoire graphique est de créer un périphérique Direct3D 12 via l’API D3D12CreateDevice. Si le titre doit allouer ou réserver de la mémoire graphique avant la création du périphérique Direct3D 12, l’API D3D12ConfigureVirtualMemoryX (XBOX Series X|S)/D3DConfigureVirtualMemory (XBOX One) peut également être utilisée pour initialiser le système de mémoire graphique. La création d’un périphérique Direct3D 12 équivaut à appeler D3D12ConfigureVirtualMemoryX avec les paramètres par défaut.Nouveaux indicateurs pour l’allocation de mémoire graphique
Une nouvelle API de titre, XMemVirtualAlloc, a été introduite pour remplacer la version étendue de VirtualAlloc présente dans l’ERA de la XBOX One. Dans le Microsoft Game Development Kit (GDK), VirtualAlloc est désormais limitée au comportement « standard » de la plateforme, identique à celui de Windows sur ordinateur de bureau. L’API VirtualFree standard est utilisée pour libérer et/ou annuler la validation de la mémoire allouée avec XMemVirtualAlloc. Une nouvelle API XMemVirtualQuery a été ajoutée pour récupérer l’ensemble complet des indicateurs de protection CPU et GPU pour une adresse virtuelle donnée. XMemVirtualAlloc accepte une nouvelle combinaison d’indicateurs XMem qui indiquent des demandes de mémoire graphique et/ou de mémoire d’outils. Un indicateur d’allocation MEM_GRAPHICS pour VirtualAlloc dans l’ERA de la XBOX One équivaut à un indicateur XMem XMEM_GRAPHICS pour XMemVirtualAlloc. Un nouvel indicateur, XMEM_GRAPHICS_32BIT_ADDRESS, combiné avec XMEM_GRAPHICS, alloue de la mémoire graphique mais limite l’adresse virtuelle attribuée automatiquement à la plage de 2 Go à 4 Go. Sans l’indicateur XMEM_GRAPHICS_32BIT_ADDRESS, les adresses virtuelles attribuées automatiquement se situent au-dessus de 4 Go et en dessous de la fin de la plage couverte par la table des pages graphiques (159 Go par défaut). L’adresse virtuelle de fin des tables de pages graphiques est définie par la quantité de mémoire dédiée aux tables de pages graphiques et peut être ajustée avant la première allocation graphique à l’aide de l’API D3D12ConfigureVirtualMemoryX. La sémantique des indicateurs de taille de page a également changé. L’ERA de la XBOX One utilisait MEM_LARGE_PAGES pour les pages de 64 Ko et MEM_4MB_PAGES pour les pages de 4 Mo. Le Microsoft Game Development Kit (GDK) utilise désormais MEM_64K_PAGES pour les pages de 64 Ko et MEM_2MB_PAGES pour les pages de 2 Mo. Notez que le code de titre existant qui utilise MEM_LARGE_PAGES doit être mis à jour avec soin et de manière exhaustive pour utiliser MEM_64K_PAGES. Les pages de 4 Mo ne sont pas prises en charge dans le Microsoft Game Development Kit (GDK). Enfin, les indicateurs de protection de page pour les graphiques ont également changé. Les indicateurs PAGE_GPU_* de l’ERA de la XBOX One ont été remplacés par une énumération PAGE_GRAPHICS_* et un indicateur PAGE_GRAPHICS_COHERENT afin de mieux correspondre aux modèles existants pour les protections de pages CPU. Toutes les allocations graphiques via XMemGraphics doivent inclure un seul des indicateurs de protection suivants :- PAGE_GRAPHICS_NOACCESS
- PAGE_GRAPHICS_READONLY
- PAGE_GRAPHICS_READWRITE
- PAGE_GRAPHICS_EXECUTE
- PAGE_GRAPHICS_EXECUTE_READ
- PAGE_GRAPHICS_EXECUTE_READWRITE
XALLOC_MEMTYPE_GRAPHICS_WRITECOMBINE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_GRAPHICS_READWRITE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_GRAPHICS_READWRITE | | Mémoire « Onion » : CPU mis en cache et GPU cohérent | XALLOC_MEMTYPE_GRAPHICS_CACHEABLE | PAGE_READWRITE | PAGE_GPU_COHERENT | PAGE_READWRITE | PAGE_GRAPHICS_COHERENT | PAGE_GRAPHICS_READWRITE | PAGE_READWRITE | PAGE_GRAPHICS_COHERENT | PAGE_GRAPHICS_READWRITE | | Mémoire tampon de commandes « Garlic » | XALLOC_MEMTYPE_GRAPHICS_COMMAND_BUFFER_WRITECOMBINE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_GPU_EXECUTE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_GRAPHICS_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_WRITECOMBINE | PAGE_GRAPHICS_EXECUTE_READWRITE | PAGE_GRAPHICS_NOCACHE | | Mémoire tampon de commandes « Onion » | XALLOC_MEMTYPE_GRAPHICS_COMMAND_BUFFER_CACHEABLE | PAGE_READWRITE | PAGE_GPU_EXECUTE | PAGE_GPU_COHERENT | PAGE_READWRITE | PAGE_GRAPHICS_EXECUTE_READWRITE | PAGE_GRAPHICS_COHERENT | PAGE_READWRITE | PAGE_GRAPHICS_EXECUTE_READWRITE | PAGE_GRAPHICS_NOCACHE | PAGE_GRAPHICS_COHERENT | | Mémoire « Garlic mise en cache » : CPU mis en cache, GPU non cohérent et en lecture seule | XALLOC_MEMTYPE_GRAPHICS_CACHEABLE_NONCOHERENT_GPU_READONLY | PAGE_READWRITE | PAGE_GPU_READONLY | PAGE_READWRITE | PAGE_GRAPHICS_READONLY | PAGE_READWRITE | PAGE_GRAPHICS_READONLY | | Mémoire de réécriture des barrières : CPU mis en cache et GPU cohérent | XALLOC_MEMTYPE_GRAPHICS_GPU_UNCACHED | n/a (XALLOC_MEMTYPE_GRAPHICS_CACHEABLE utilisé) | PAGE_READWRITE | PAGE_GRAPHICS_COHERENT | PAGE_GRAPHICS_READWRITE | PAGE_READWRITE | PAGE_GRAPHICS_COHERENT | PAGE_GRAPHICS_NOCACHE | PAGE_GRAPHICS_READWRITE |
XMemAlloc pour le Microsoft Game Development Kit (GDK)
Le tas de mémoire en mode utilisateur XMemAlloc a été intégré au Microsoft Game Development Kit (GDK) avec un minimum de modifications. Il réside désormais dans sa propre DLL (xmem.dll) et sa propre bibliothèque de liaison (xmem.lib). Les API XMemAlloc existantes, notamment XMemAlloc, XMemFree et XMemSetAllocationHooks, sont toujours présentes et fonctionnent de la même façon que dans l’ERA de la XBOX One. Un nouvel indicateur Address32BitMapping a été ajouté à la structure XALLOC_ATTRIBUTES passée à XMemAlloc et à XMemFree. Ce nouvel indicateur signale que l’appelant souhaite allouer de la mémoire et que cette allocation doit avoir une adresse 32 bits. Le pilote graphique en mode utilisateur Direct3D 12 du Microsoft Game Development Kit (GDK) utilise cet indicateur lors de la création d’allocations de mémoire spécifiques, notamment les tas de descripteurs et la mémoire des objets d’état de pipeline. Ces allocations ont une longue durée de vie et sont toujours alignées sur des pages de 64 Ko ; elles n’ont donc pas besoin d’être gérées dans un tas. Les demandes d’allocation peuvent plutôt être transmises à XMemVirtualAlloc avec l’indicateur XMEM_GRAPHICS_32BIT_ADDRESS. Le pilote graphique Direct3D 12 de l’ERA de la XBOX One utilisait en arrière-plan un mécanisme complexe et coûteux pour remapper des allocations de titre arbitraires dans l’espace d’adressage 32 bits, sans que l’implémentation XMemAlloc ni le titre n’aient connaissance du besoin d’adresses 32 bits. Le pilote graphique du Microsoft Game Development Kit (GDK) a abandonné ce système complexe au profit d’une approche beaucoup plus simple et plus rapide, qui communique clairement au titre et à l’implémentation XMemAlloc le besoin d’une allocation 32 bits.Modifications de la mémoire des tas de descripteurs de Direct3D 12.X
Le pilote graphique Direct3D 12.X de l’ERA de la XBOX One créait un second alias de mémoire mis en cache côté CPU et en lecture seule pour tous les tas de descripteurs visibles par le GPU. Le code qui lisait des descripteurs sur le CPU utilisait cet alias en lecture seule mis en cache pour améliorer les performances de lecture du CPU. Ce second alias de mémoire n’existe plus dans le Microsoft Game Development Kit (GDK) ; toute lecture CPU à partir de tas de descripteurs visibles par le GPU est donc une lecture CPU non mise en cache depuis une mémoire en écriture combinée. Notez que les tas de descripteurs de cibles de rendu et de profondeur/gabarit (D3D12_DESCRIPTOR_HEAP_TYPE_RTV et D3D12_DESCRIPTOR_HEAP_TYPE_DSV) sont toujours créés en mémoire mise en cache côté CPU, qu’ils soient créés comme visibles par le GPU ou non.Prise en charge de la mémoire « Garlic mise en cache » sur XBOX One et XBOX Series X|S
Sur XBOX One, le Microsoft Game Development Kit (GDK) ne prend plus en charge la création de mappages de mémoire mis en cache et en lecture seule côté CPU, et non cohérents et en lecture-écriture côté GPU. Les indicateurs de protection de page du Microsoft Game Development Kit (GDK) utilisés pour cette combinaison interdite sontPAGE_READONLY | PAGE_GRAPHICS_READWRITE.
Sur XBOX Series X|S, le Microsoft Game Development Kit (GDK) prend en charge la création des 3 types de mappages de mémoire mis en cache et non cohérents. Ces 3 types sont : CPU en lecture-écriture et GPU en lecture seule, CPU en lecture seule et GPU en lecture-écriture, et CPU en lecture-écriture et GPU en lecture-écriture. Lors de l’utilisation de ces types de mémoire graphique, des précautions particulières doivent être prises pour éviter une corruption de la mémoire due à la mise en cache non cohérente par le CPU et le GPU.
Gardez à l’esprit les règles suivantes lors de l’utilisation de la mémoire garlic mise en cache :
- Avant de lire ou d’écrire dans la mémoire garlic mise en cache, sur le CPU ou le GPU, videz les caches.
- Une fois les écritures dans la mémoire garlic mise en cache terminées, sur le CPU ou le GPU, videz les caches.
- Utilisez des primitives de synchronisation pour contrôler l’accès exclusif en écriture à la mémoire garlic mise en cache. Évitez les écritures simultanées provenant de plusieurs clients.
- Lorsque vous examinez les modèles d’accès en lecture/écriture, raisonnez sur des lignes de cache entières de 64 octets à la fois, car c’est l’unité de mémoire chargée dans les caches CPU et GPU, puis réécrite. Il n’est pas toujours possible de garantir que des écritures partielles de lignes de cache sont générées par le CPU ou le GPU, en particulier pour la mémoire mise en cache.
