2010-05-18 31 views
10

Trong Mac OS X, mọi màn hình hiển thị được gán số CGDirectDisplayID duy nhất được gán cho nó. Bạn có thể sử dụng CGGetActiveDisplayList() hoặc [NSScreen screens] để truy cập chúng, trong số những thứ khác. Mỗi Apple's docs:Làm thế nào để giải quyết các vấn đề thay đổi CGDirectDisplayID trên máy tính xách tay Apple Multi-GPU mới hơn trong Core Foundation/IO Kit?

Một ID hiển thị có thể tồn tại trên quy trình và hệ thống khởi động lại, và thường vẫn không đổi chừng nào thông số hiển thị nhất định không thay đổi.

Vào phiên bản MacBook Pro mới hơn giữa năm 2010, Apple bắt đầu sử dụng tự động chuyển đồ họa Intel/nVidia. Máy tính xách tay có hai GPU, một Intel hỗ trợ thấp và một nVidia hỗ trợ cao. Máy tính xách tay dual-GPU trước đây (kiểu 2009) không có chuyển đổi tự động GPU, và yêu cầu người dùng thực hiện thay đổi cài đặt, đăng xuất và sau đó đăng nhập lại để thực hiện chuyển đổi GPU. Ngay cả các hệ thống cũ hơn chỉ có một GPU.

Có vấn đề với các mô hình giữa năm 2010, nơi CGDirectDisplayID không giữ nguyên khi màn hình chuyển từ GPU này sang GPU khác. Ví dụ:

  1. Bật máy tính xách tay.
  2. Được xây dựng trong LCD Màn hình được điều khiển bởi chipset Intel. hiển thị ID:
  3. ngoài Display được cắm vào
  4. Built-In Screen LCD chuyển sang nVidia chipset.. Nó hiển thị ID thay đổi: Hiển thị
  5. ngoài được thúc đẩy bởi chipset nVidia.
  6. ... tại thời điểm này, chipset Intel không hoạt động ...
  7. Ngắt người dùng Hiển thị bên ngoài.
  8. Được xây dựng trong Màn hình LCD chuyển về Chipset Intel. Nó hiển thị ID thay đổi trở lại ban đầu:

Câu hỏi của tôi là, làm thế nào tôi có thể phù hợp với một ID hiển thị cũ sang một ID hiển thị mới khi họ thay đổi do sự thay đổi GPU?


tưởng về:

tôi đã nhận thấy rằng màn hình hiển thị ID chỉ thay đổi bằng 2, nhưng tôi không có đủ thử nghiệm Mac có sẵn để xác định xem đây là chung cho tất cả MacBook mới Pro, hay chỉ là của tôi. Loại một kludge nếu "chỉ cần kiểm tra cho ID hiển thị của là +/- 2 từ nhau" công trình, anyway.


Cố gắng:

CGDisplayRegisterReconfigurationCallback(), mà thông báo trước và sau khi màn hình sẽ thay đổi, không có lý phù hợp. Đưa một cái gì đó như thế này bên trong một phương pháp đăng ký với nó không hoạt động:

// Run before display settings change: 
CGDirectDisplayID directDisplayID = ...; 
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID); 
CFDictionaryRef oldInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo); 

// ...display settings change... 

// Run after display settings change: 
CGDirectDisplayID directDisplayID = ...; 
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID); 
CFDictionaryRef newInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo); 
BOOL match = IODisplayMatchDictionaries(oldInfoDict, newInfoDict, 0); 

if (match) 
    NSLog(@"Displays are a match"); 
else 
    NSLog(@"Displays are not a match"); 

gì đang xảy ra ở trên là:

  1. Tôi nhớ đệm oldInfoDict trước khi cài đặt hiển thị thay đổi.
  2. Chờ cài đặt màn hình để thay đổi
  3. Sau đó so sánh oldInfoDict để newInfoDict bằng cách sử dụng IODisplayMatchDictionaries()
  4. IODisplayMatchDictionaries() trả về một BOOL, hoặc YES họ là giống nhau, hoặc NO họ khác nhau.

Thật không may, IODisplayMatchDictionaries() không trả lại CÓ nếu cùng một màn hình thay đổi GPU. Dưới đây là một ví dụ của từ điển của nó so sánh (nhìn vào phím IODisplayLocation):

// oldInfoDict (Display ID: 30002) 
oldInfoDict: { 
    DisplayProductID = 40144; 
    DisplayVendorID = 1552; 
    IODisplayLocation = "IOService:/AppleACPIPlatformExpert/[email protected]/AppleACPIPCI/[email protected]/AppleIntelFramebuffer/display0/AppleBacklightDisplay"; 
} 

// newInfoDict (Display ID: 30004) 
newInfoDict: { 
    DisplayProductID = 40144; 
    DisplayVendorID = 1552; 
    IODisplayLocation = "IOService:/AppleACPIPlatformExpert/[email protected]/AppleACPIPCI/[email protected]/IOPCI2PCIBridge/[email protected]/NVDA,[email protected]/NVDA/display0/AppleBacklightDisplay"; 
} 

Như bạn có thể thấy, IODisplayLocation thay đổi quan trọng khi của GPU được bật, do đó IODisplayMatchDictionaries() không hoạt động.

Về mặt lý thuyết, tôi có thể so sánh chỉ với các phím DisplayProductIDDisplayVendorID nhưng tôi đang viết phần mềm người dùng cuối và lo lắng về tình huống mà người dùng có hai hoặc nhiều màn hình giống nhau được cắm vào (nghĩa là cả hai đều có cùng DisplayProductID/DisplayVendorID). Nói cách khác, đó là một giải pháp ít hơn so với hoàn hảo mở cho những trục trặc tiềm ẩn.


Bất kỳ trợ giúp nào được đánh giá cao! :)

Trả lời

1

Trong khi tôi không chuyên nghiệp, tôi tin rằng câu trả lời là cho phép Apple notify bạn khi người dùng thay đổi hiển thị. Thông tin inf gọi lại chứa cờ để thêm và xóa CGDirectDisplayID s.

Người dùng không nên thêm hoặc xóa thẻ đồ họa trong khi hoạt động, vì vậy tôi sẽ phát danh sách khi khởi động và bất cứ khi nào bạn nhận được cờ "xóa", hãy đặt thao tác "thêm" tiếp theo để thay thế ID đó trong danh sách.

Tôi chỉ muốn in thông tin bạn nhận được mỗi lần CGDisplayRegisterReconfigurationCallback gọi hàm của bạn. Xem liệu bạn có nhận được một thiết bị có DeviceUID có cờ 'xóa' không và sau đó một cuộc gọi tiếp theo khác có cờ 'thêm'. Việc kiểm tra các id đó với số CGGetActiveDisplayList cũng sẽ giúp hiểu được những gì đang diễn ra.

Đó là đặt cược tốt nhất của tôi, hy vọng điều đó sẽ hữu ích!

+2

Cảm ơn Stephen. Đáng buồn thay, thông báo không có bất cứ điều gì nói rằng "DisplayID ABC bây giờ đã trở thành DisplayID XYZ". Những gì tôi đã phát hiện ra kể từ khi đăng câu hỏi này là ID hiển thị có thể thay đổi động tại thời gian chạy bất kỳ lúc nào. Ví dụ, nếu bạn khởi động Adobe Photoshop CS4, giữa năm 2010, MacBook Pro chuyển từ đồ họa tích hợp Intel sang đồ họa rời nVidia. Điều này có ý nghĩa vì Photoshop CS4 + là GPU chuyên sâu. Tuy nhiên, displayID cho màn hình của bạn thay đổi trong khi chuyển mạch GPU. Một khi bạn tồn tại Photoshop, nó rơi trở lại GPU Intel, và displayID thay đổi một lần nữa. Vui vẻ! :) –

+0

Đúng, nhưng bạn vẫn sẽ nhận được một cuộc gọi lại để xóa ID và một cho ID thêm, không? –

2

Tôi đã không tìm thấy cách nào tốt hơn con số mà bạn liệt kê là "Đã cố gắng". Nhưng tôi đã tìm thấy một giải pháp cho vấn đề mơ hồ khi so sánh chỉ id nhà cung cấp và id sản phẩm.

oldInfoDictnewInfoDict trong mã của bạn chứa một mục bổ sung cho chính kIODisplayEDIDKey (quy định tại IOGraphicsTypes.h) chứa EDID của mỗi màn hình được kết nối. Quan sát của tôi cho thấy rằng toàn bộ dữ liệu này vẫn liên tục giữa các chuyển mạch GPU. Ví dụ:

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

Nhìn vào mô tả dữ liệu của EDID trong Wikipedia, blob này đã chứa nhà sản xuất, id sản phẩm và sê-ri. Vì vậy, nó đủ để so sánh màn hình bằng cách sử dụng dữ liệu EDID (hoặc ví dụ một hash của nó nếu bạn chỉ muốn so sánh một số ngắn hơn).

Các vấn đề liên quan