Skip to content

Instantly share code, notes, and snippets.

@Akemi
Last active September 13, 2022 00:20
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Akemi/185d83afbef47c0c8e0add2a3c99b6d2 to your computer and use it in GitHub Desktop.
Save Akemi/185d83afbef47c0c8e0add2a3c99b6d2 to your computer and use it in GitHub Desktop.
macOS EDR Test
import Cocoa
import OpenGL.GL
import OpenGL.GL3
extension NSDeviceDescriptionKey {
static let screenNumber = NSDeviceDescriptionKey("NSScreenNumber")
}
extension NSScreen {
public var displayID: CGDirectDisplayID {
get {
return deviceDescription[.screenNumber] as? CGDirectDisplayID ?? 0
}
}
public var displayName: String? {
get {
var name: String? = nil
var object: io_object_t
var iter = io_iterator_t()
let matching = IOServiceMatching("IODisplayConnect")
let result = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iter)
if result != KERN_SUCCESS || iter == 0 { return nil }
repeat {
object = IOIteratorNext(iter)
if let info = IODisplayCreateInfoDictionary(object, IOOptionBits(kIODisplayOnlyPreferredName)).takeRetainedValue() as? [String:AnyObject],
(info[kDisplayVendorID] as? UInt32 == CGDisplayVendorNumber(displayID) &&
info[kDisplayProductID] as? UInt32 == CGDisplayModelNumber(displayID) &&
info[kDisplaySerialNumber] as? UInt32 ?? 0 == CGDisplaySerialNumber(displayID))
{
if let productNames = info["DisplayProductName"] as? [String:String],
let productName = productNames.first?.value
{
name = productName
break
}
}
} while object != 0
IOObjectRelease(iter)
return name
}
}
}
let glVersions: [CGLOpenGLProfile] = [
kCGLOGLPVersion_3_2_Core,
kCGLOGLPVersion_Legacy
]
let glFormatBase: [CGLPixelFormatAttribute] = [
kCGLPFAOpenGLProfile,
kCGLPFAAccelerated,
kCGLPFADoubleBuffer
]
let glFormatSoftwareBase: [CGLPixelFormatAttribute] = [
kCGLPFAOpenGLProfile,
kCGLPFARendererID,
CGLPixelFormatAttribute(UInt32(kCGLRendererGenericFloatID)),
kCGLPFADoubleBuffer
]
let glFormatOptional: [[CGLPixelFormatAttribute]] = [
[kCGLPFABackingStore],
[kCGLPFAAllowOfflineRenderers],
[kCGLPFASupportsAutomaticGraphicsSwitching]
]
let glFormat10Bit: [CGLPixelFormatAttribute] = [
kCGLPFAColorSize,
_CGLPixelFormatAttribute(rawValue: 64),
kCGLPFAColorFloat
]
let attributeLookUp: [UInt32:String] = [
kCGLOGLPVersion_3_2_Core.rawValue: "kCGLOGLPVersion_3_2_Core",
kCGLOGLPVersion_Legacy.rawValue: "kCGLOGLPVersion_Legacy",
kCGLPFAOpenGLProfile.rawValue: "kCGLPFAOpenGLProfile",
UInt32(kCGLRendererGenericFloatID): "kCGLRendererGenericFloatID",
kCGLPFARendererID.rawValue: "kCGLPFARendererID",
kCGLPFAAccelerated.rawValue: "kCGLPFAAccelerated",
kCGLPFADoubleBuffer.rawValue: "kCGLPFADoubleBuffer",
kCGLPFABackingStore.rawValue: "kCGLPFABackingStore",
kCGLPFAColorSize.rawValue: "kCGLPFAColorSize",
kCGLPFAColorFloat.rawValue: "kCGLPFAColorFloat",
kCGLPFAAllowOfflineRenderers.rawValue: "kCGLPFAAllowOfflineRenderers",
kCGLPFASupportsAutomaticGraphicsSwitching.rawValue: "kCGLPFASupportsAutomaticGraphicsSwitching",
]
class Layer: CAOpenGLLayer {
let view: View
var vbo: GLuint = 0
var vao: GLuint = 0
let vertexShaderSource: NSString = """
#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;
out vec4 fragColor;
void main()
{
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
fragColor = vec4(color.x, color.y, color.z, 1.0f);
}
"""
let fragmentShaderSource: NSString = """
#version 330 core
in vec4 fragColor;
out vec4 color;
void main()
{
color = fragColor;
}
"""
let vertices: [GLfloat] = [
// top left white rectangle
// two values position
// three values color
-1.0, 1.0,
1.0, 1.0, 1.0,
0.0, 1.0,
1.0, 1.0, 1.0,
0.0, 0.0,
1.0, 1.0, 1.0,
-1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 0.0,
1.0, 1.0, 1.0,
0.0, 0.0,
1.0, 1.0, 1.0,
// bottom left ultra white rectangle
-1.0, 0.0,
2.0, 2.0, 2.0,
0.0, 0.0,
2.0, 2.0, 2.0,
0.0, -1.0,
2.0, 2.0, 2.0,
-1.0, 0.0,
2.0, 2.0, 2.0,
-1.0, -1.0,
2.0, 2.0, 2.0,
0.0, -1.0,
2.0, 2.0, 2.0,
// bottom right 50% gray rectangle
0.0, 0.0,
0.5, 0.5, 0.5,
1.0, 0.0,
0.5, 0.5, 0.5,
1.0, -1.0,
0.5, 0.5, 0.5,
0.0, 0.0,
0.5, 0.5, 0.5,
0.0, -1.0,
0.5, 0.5, 0.5,
1.0, -1.0,
0.5, 0.5, 0.5,
]
let verticesStride: Int = 2
let colorStride: Int = 3
var dataStride: Int { get { return verticesStride + colorStride } }
init(_ vview: View, _ edr: Bool = false) {
view = vview
super.init()
autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
backgroundColor = NSColor.black.cgColor
wantsExtendedDynamicRangeContent = edr
isAsynchronous = true
if #available(macOS 10.12, *) {
contentsFormat = .RGBA16Float
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func canDraw(inCGLContext ctx: CGLContextObj,
pixelFormat pf: CGLPixelFormatObj,
forLayerTime t: CFTimeInterval,
displayTime ts: UnsafePointer<CVTimeStamp>?) -> Bool {
return true
}
override func draw(inCGLContext ctx: CGLContextObj,
pixelFormat pf: CGLPixelFormatObj,
forLayerTime t: CFTimeInterval,
displayTime ts: UnsafePointer<CVTimeStamp>?) {
CGLSetCurrentContext(ctx);
// create shaders
let vertexShader = glCreateShader(GLenum(GL_VERTEX_SHADER))
var vxsCS = vertexShaderSource.utf8String
glShaderSource(vertexShader, 1, &vxsCS, nil)
glCompileShader(vertexShader)
checkShaderError(vertexShader)
let fragmentShader = glCreateShader(GLenum(GL_FRAGMENT_SHADER))
var fsCS = fragmentShaderSource.utf8String
glShaderSource(fragmentShader, 1, &fsCS, nil)
glCompileShader(fragmentShader)
checkShaderError(fragmentShader)
// attach shaders to program
let shaderProgram = glCreateProgram()
defer { glDeleteProgram(shaderProgram) }
glAttachShader(shaderProgram, vertexShader)
glAttachShader(shaderProgram, fragmentShader)
glLinkProgram(shaderProgram)
checkProgramError(shaderProgram)
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
// bind shader data
glGenVertexArrays(1, &vao)
glGenBuffers(1, &vbo)
defer { glDeleteVertexArrays(1, &vao) }
defer { glDeleteBuffers(1, &vbo) }
let glfloatStride = MemoryLayout<GLfloat>.stride
glBindVertexArray(vao)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vbo)
glBufferData(GLenum(GL_ARRAY_BUFFER), glfloatStride * vertices.count, vertices, GLenum(GL_STATIC_DRAW))
// postion data
glVertexAttribPointer(
0,
GLint(verticesStride),
GLenum(GL_FLOAT),
GLboolean(GL_FALSE),
GLsizei(glfloatStride * dataStride),
nil
)
// color data
glVertexAttribPointer(
1,
GLint(colorStride),
GLenum(GL_FLOAT),
GLboolean(GL_FALSE),
GLsizei(glfloatStride * dataStride),
UnsafeRawPointer(bitPattern: glfloatStride * verticesStride)
)
glEnableVertexAttribArray(0)
glEnableVertexAttribArray(1)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindVertexArray(0)
// clear
glClearColor(0, 0, 0.0, 1)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))
// draw
glUseProgram(shaderProgram)
glBindVertexArray(vao)
glDrawArrays(GLenum(GL_TRIANGLES), 0, GLsizei(vertices.count/2))
glBindVertexArray(0)
CGLFlushDrawable(ctx)
}
func checkShaderError(_ shader: GLuint) {
var success:GLint = 0
var infoLog = [GLchar](repeating: 0, count: 512)
glGetShaderiv(shader, GLenum(GL_COMPILE_STATUS), &success)
guard success == GL_TRUE else
{
glGetShaderInfoLog(shader, 512, nil, &infoLog)
fatalError(String(cString:infoLog))
}
}
func checkProgramError(_ program: GLuint) {
var success:GLint = 0
var infoLog = [GLchar](repeating: 0, count: 512)
glGetProgramiv(program, GLenum(GL_LINK_STATUS), &success)
guard success == GL_TRUE else
{
glGetProgramInfoLog(program, 512, nil, &infoLog)
fatalError(String(cString:infoLog))
}
}
override func copyCGLPixelFormat(forDisplayMask mask: UInt32) -> CGLPixelFormatObj {
print("--------- Layer with EDR: \(wantsExtendedDynamicRangeContent) ---------")
print("--------- View with EDR: \(view.wantsExtendedDynamicRangeOpenGLSurface) ---------")
let (cglPixelFormat, bufferDepth) = Layer.createPixelFormat()
return cglPixelFormat
}
override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj {
let ctx = Layer.createContext(pf)
return ctx
}
class func createPixelFormat() -> (CGLPixelFormatObj, GLint) {
var pix: CGLPixelFormatObj?
var depth: GLint = 8
var err: CGLError = CGLError(rawValue: 0)
let swRender = 0
(pix, depth, err) = Layer.findPixelFormat()
guard let pixelFormat = pix, err == kCGLNoError else {
print("Couldn't create any CGL pixel format")
exit(1)
}
return (pixelFormat, depth)
}
class func findPixelFormat(_ software: Bool = false) -> (CGLPixelFormatObj?, GLint, CGLError) {
var pix: CGLPixelFormatObj?
var err: CGLError = CGLError(rawValue: 0)
var npix: GLint = 0
for ver in glVersions {
var glBase = software ? glFormatSoftwareBase : glFormatBase
glBase.insert(CGLPixelFormatAttribute(ver.rawValue), at: 1)
var glFormat = [glBase]
glFormat += [glFormat10Bit]
glFormat += glFormatOptional
for index in stride(from: glFormat.count-1, through: 0, by: -1) {
let format = glFormat.flatMap { $0 } + [_CGLPixelFormatAttribute(rawValue: 0)]
err = CGLChoosePixelFormat(format, &pix, &npix)
if err == kCGLBadAttribute || err == kCGLBadPixelFormat || pix == nil {
glFormat.remove(at: index)
} else {
let attArray = format.map({ (value: _CGLPixelFormatAttribute) -> String in
return attributeLookUp[value.rawValue] ?? String(value.rawValue)
})
print("Created CGL pixel format with attributes: " +
"\(attArray.joined(separator: ", "))")
return (pix, glFormat.contains(glFormat10Bit) ? 16 : 8, err)
}
}
}
let errS = String(cString: CGLErrorString(err))
print("Couldn't create a " +
"\(software ? "software" : "hardware accelerated") " +
"CGL pixel format: \(errS) (\(err.rawValue))")
return (pix, 8, err)
}
class func createContext(_ pixelFormat: CGLPixelFormatObj) -> CGLContextObj {
var context: CGLContextObj?
let error = CGLCreateContext(pixelFormat, nil, &context)
guard let cglContext = context, error == kCGLNoError else {
let errS = String(cString: CGLErrorString(error))
print("Couldn't create a CGLContext: " + errS)
exit(1)
}
return cglContext
}
}
class View: NSView {
init(frame frameRect: NSRect, _ edr: Bool = false) {
super.init(frame:frameRect)
autoresizingMask = [.width, .height]
wantsBestResolutionOpenGLSurface = true
wantsExtendedDynamicRangeOpenGLSurface = edr
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class Window: NSWindow, NSWindowDelegate {
override var canBecomeKey: Bool { return true }
override var canBecomeMain: Bool { return true }
override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask,
backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
super.init(contentRect:contentRect, styleMask:style, backing:backingStoreType, defer:flag)
minSize = NSMakeSize(200, 200)
makeMain()
makeKeyAndOrderFront(nil)
delegate = self
contentAspectRatio = contentView!.frame.size
}
}
class App: NSApplication, NSApplicationDelegate {
var window: Window?
var window2: Window?
func applicationDidFinishLaunching(_ notification: Notification) {
print("----------------------------- BEFORE EDR REQUEST ------------------------------")
printEDRScreenData()
print("-------------------------------------------------------------------------------")
NSApp.setActivationPolicy(.regular)
atexit_b { NSApp.setActivationPolicy(.prohibited) }
window = Window(
contentRect: NSMakeRect(0, 300, 1000, 500),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false
)
let view = View(frame: window?.contentView?.bounds ?? NSMakeRect(0, 300, 1000, 500))
window?.contentView?.addSubview(view)
window?.title = "EDR deactivated"
view.layer = Layer(view)
view.wantsLayer = true
window2 = Window(
contentRect: NSMakeRect(1000, 300, 1000, 500),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false
)
let view2 = View(frame: window?.contentView?.bounds ?? NSMakeRect(1000, 300, 1000, 500), true)
window2?.contentView?.addSubview(view2)
window2?.title = "EDR activated"
view2.layer = Layer(view2, true)
view2.wantsLayer = true
NSApp.activate(ignoringOtherApps: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
print("------------------------------ AFTER EDR REQUEST ------------------------------")
self.printEDRScreenData()
print("-------------------------------------------------------------------------------")
}
}
func printEDRScreenData() {
for screen in NSScreen.screens {
var maxPot: CGFloat = -1.0
var maxRef: CGFloat = -1.0
var maxRange: CGFloat = -1.0
print(screen.displayName ?? "unknown")
if #available(macOS 10.15, *) {
maxPot = screen.maximumPotentialExtendedDynamicRangeColorComponentValue
maxRef = screen.maximumReferenceExtendedDynamicRangeColorComponentValue
}
maxRange = screen.maximumExtendedDynamicRangeColorComponentValue
print("maximumPotentialExtendedDynamicRangeColorComponentValue: \(maxPot)")
print("maximumReferenceExtendedDynamicRangeColorComponentValue: \(maxRef)")
print("maximumExtendedDynamicRangeColorComponentValue: \(maxRange)")
}
}
}
let app = App.shared
NSApp = app
app.delegate = app as? NSApplicationDelegate
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment