12
votes

Comment résoudre les problèmes changeants CGDirectDisplayID sur les ordinateurs portables Apple plus récent multi-GPU dans Core Foundation / Io Kit?

Dans Mac OS X, chaque affichage obtient un numéro CGDirectDisplayID (code> CGDirectDisplayID code> attribué à celui-ci. Vous pouvez utiliser cggetactiveSisplayList ( code>) ou [écrans nscreen] code> pour y accéder, entre autres. Par Documents d'Apple :

Un identifiant d'affichage peut persister à travers processus et redémarrage du système, et reste généralement constant aussi longtemps que Certains paramètres d'affichage ne font pas changer. p> BlockQuote>

On Newer Mid-2010 MacBook Pro, Apple a commencé à utiliser l'interrupteur automatique Intel / Nvidia Graphics. Les ordinateurs portables ont deux GPU, un Intel à faible consommation et une Nvidia à haute puissance. Les ordinateurs portables Dual-GPU précédents (modèles 2009) n'ont pas eu la commutation GPU Auto-GPU et l'utilisateur de modifier, déconnectez-vous, puis de vous connecter à nouveau pour effectuer un commutateur GPU. Même les systèmes plus anciens n'avaient qu'un GPU. P>

Il y a un problème avec les modèles de la mi-2010 où CGDirectDisplayID ne reste pas la même lorsque un écran passe d'un GPU à l'autre. Par exemple: p>

  1. Pouvoir Ordinateur portable sur. Li>
  2. intégré LCD L'écran strong> est conduit par un chipset Intel. ID d'affichage: 30002 strong> li>
  3. externe Affichage strong> est branché. LI>
  4. intégré Écran LCD STRAND> Basculements sur NVIDIA chipset. Il s'agit de modifications d'identification d'affichage: 30004 strong> li>
  5. Affichage externe fort> est conduit par Nvidia Chipset. Li>
  6. ... à ce stade, Le chipset Intel est dormant ... Li>
  7. utilisateur débranchit Affichage externe fort>. LI>
  8. Écran LCD intégré STRT> retourne à Chipset Intel. C'est l'identifiant d'affichage Retour à l'original: 30002 strong> li> ol>

    Ma question est, comment puis-je correspondre à un ancien ID d'affichage à un nouvel identifiant d'affichage lorsqu'il est modifié en raison d'un changement de GPU? strong> p>


    pensée à propos de: strong> p>

    J'ai remarqué que l'identifiant d'affichage n'envoie que 2, mais je n'ai pas assez de test Mac disponible pour déterminer si cela est commun à tout le nouveau MacBook Pro est, ou juste le mien. Type d'un kludge si "Vérifiez simplement les identifiants d'affichage qui sont +/- 2 les uns des autres" fonctionne, de toute façon. P>


    Essayé: p> P> P> P> P> P > cgdisplayregisterReconfigurationCallback () code>, qui notifie avant-et-après lorsque les affichages vont changer, aucune logique correspondante. Mettre quelque chose comme ça à l'intérieur d'une méthode enregistrée ne fonctionne pas: P>

    // oldInfoDict  (Display ID: 30002)
    oldInfoDict: {
        DisplayProductID = 40144;
        DisplayVendorID = 1552;
        IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/IGPU@2/AppleIntelFramebuffer/display0/AppleBacklightDisplay";
    }
    
    // newInfoDict  (Display ID: 30004)
    newInfoDict: {
        DisplayProductID = 40144;
        DisplayVendorID = 1552;
        IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/P0P2@1/IOPCI2PCIBridge/GFX0@0/NVDA,Display-A@0/NVDA/display0/AppleBacklightDisplay";
    }
    


1 commentaires

Lorsqu'un changement de GPU se produit, les drapeaux envoyés au rappel incluent un non-documenté: #define kcgdisplaymysterygpugedflag (1 << 13) // drapeau de rappel post-reconfiguration non documenté pour systèmes I5 / I7


4 Réponses :


1
votes

Bien que je ne suis pas pro, je pense que la réponse est d'autoriser Apple Avertissez vous lorsque l'utilisateur change d'affichage. L'INFO INF Le rappel contient des indicateurs pour ajouter et supprimer cgdirectdisplayID s.

L'utilisateur ne doit pas ajouter ou supprimer des cartes graphiques pendant le fonctionnement. Je vais donc jouer avec la liste de fabrication au démarrage, et chaque fois que vous obtenez le drapeau "Supprimer" définir l'opération "Ajouter" suivante pour remplacer cet ID dans la liste. .

J'essaierais d'imprimer des informations que vous récupérez chaque fois que cgdisplayregisterReconfigurationCallback appelle votre fonction. Voyez si vous en obtenez un avec un appareil avec un drapeau "Supprimer", puis un appel ultérieur d'un autre avec un drapeau "Ajouter". Vérification de ces identifiants contre cggetactiveSisplayList aiderait également à comprendre ce qui se passe.

C'est mon meilleur pari, espérons que cela aide!


3 commentaires

Merci Stephen. Malheureusement, la notification n'a rien de dire "DisplayID ABC est devenu affichée XYZ". Ce que j'ai découvert depuis l'affichage de cette question est l'identifiant d'affichage peut changer de manière dynamique à l'exécution à tout moment. Par exemple, si vous lancez Adobe Photoshop CS4, le commutateur MacBook Pro Mid-2010 de Intel intégré Graphics à Nvidia discret graphique. Cela a du sens puisque Photoshop CS4 + est intensive GPU. Cependant, l'affichage pour votre moniteur change lors de commutateurs GPU. Une fois que vous existez Photoshop, il retombe au GPU Intel, et le displayID change à nouveau. Amusant! :)


True, mais vous devriez toujours obtenir un rappel pour l'ID Supprimer et un pour l'identifiant Ajouter, non?


@DaveGallagher Avez-vous essayé d'utiliser cfuuidref? Cfuuidref de mon expérience anecdotique a toujours été cohérent, même lorsque CGDirectDisplayID change, même à travers les redémarrages.



4
votes

Je n'ai trouvé aucun moyen de mieux que vous lisez comme "essayé". Mais j'ai trouvé une solution pour la question de l'ambiguïté de comparer uniquement l'ID de fournisseur et l'ID de produit.

oldinfodict code> et newinfodict code> dans votre code contient une entrée supplémentaire pour la clé kiodispleedidkkey code> (défini dans iographicstypes .h ) qui contient le EDID de chaque écran connecté. Mes observations montrent que ces données comme un reste persistante entre les commutateurs GPU. Par exemple: P>

    CGDirectDisplayID displayId = [[[screen deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue];
    io_service_t displayPort = CGDisplayIOServicePort(displayId);

    if (displayPort == MACH_PORT_NULL)
        return nil;  // No physical device to get a name from.

    CFDictionaryRef infoDict = IODisplayCreateInfoDictionary(displayPort, kIODisplayOnlyPreferredName);

    NSData *displayEdid = (NSData *)CFDictionaryGetValue(infoDict, CFSTR(kIODisplayEDIDKey));
    NSLog(@"EDID: %@", displayEdid);

    CFRelease(infoDict);


3 commentaires

Savez-vous si le blob de données EDID est unique pour chaque affichage ? C'est-à-dire que deux écrans Thunderbolt aura-t-il différentes blobs EDID? Notez que le "numéro de série" est toujours zéro, de sorte qu'un autre aspect de l'EDID doit être différent. Fondamentalement, je cherche un moyen fiable d'identifier le même écran physique dans toutes les conditions.


Voulez-vous dire deux modèles d'affichage identiques connectés sur Thunderbolt? Si ce n'est pas le même modèle ni même différents fournisseurs, je suis à peu près sûr que l'EDID sera différent. Si c'est la même marque et le même modèle, et que la série n'est pas peuplée, il peut être difficile de les distinguer. La série étant zéro pourrait être un problème spécifique du fournisseur, avez-vous essayé différents écrans?


Je n'ai pas essayé d'autres fournisseurs, mais les écrans d'Apple ont définitivement le numéro de série défini à zéro.



7
votes

Utilisez cfuuidref qui peut être obtenu en utilisant:

cgdisplaycreaueuidfromdisplayID (CGDirectDisplayID displayID) et vous pouvez récupérer l'affichage à l'aide de:

cgdisplayGetDisplayIDFromuuid (UUID CFUUIDREF)

C'est ce que j'utilise pour identifier de manière unique des écrans, même lorsque leurs modifications de CGDirectDisplayID, par exemple ont été branchées dans un autre port. Ces fonctions ne sont pas correctement documentées par Apple malheureusement, mais mes tests sur plusieurs Mac avec plusieurs écrans montrent que le CFUUIDREF obtenu est unique et cohérent après un redémarrage-, quel que soit le cas de la cgdirectDisplayID de quelque raison que ce soit.

Pour vérifier si un affichage est neuf / unique, prenez son CGDirectDisplayID et la convertissez-le en CFUUIDREF, puis comparez l'UUID, il s'agit d'une relation multiple à une, de nombreux CGDirectDisplayIDS planeront dans un seul CFUUIDRF.

Ces appels d'API sont disponibles dans ApplicationsVices en 10.7 - 10.12 et ColorSync depuis 10.13.


0 commentaires

0
votes

J'ai utilisé: xxx

Toutefois, lors d'un événement d'élimination de l'affichage dans le rappel, même pendant le kcgdisplaybeginconfigurationflag , l'appel à cgdisplaycreauuidfromdisplayID échoue avec une erreur "displayid invalide", donc je ne vois donc aucun moyen de passer d'un CGDirectDisplayID ambigu à une UUID stable lorsqu'un écran est enlevé.

intéressant, on peut toujours obtenir le Array de Nscreens et recherchez une correspondance du CGDirectDisplayID:

[[[[[[Écran DeviceDescription] ObjectForkey: @ "Nscreennumber"] UnsignedLongValue]

en xcode le nscreen a une propriété appelée _uuidstring qui contient le même uuid mais je ne vois aucun moyen d'obtenir cet uuid hors du Nscreen.


0 commentaires