Delve into the world of graphics and game development. Discuss creating stunning visuals, optimizing game mechanics, and share resources for game developers.

All subtopics
Posts under Graphics & Games topic

Post

Replies

Boosts

Views

Activity

Doc bug? Any reason to use Metal's wantsExtendedDynamicRangeContent instead of CALayer preferredDynamicRange?
Should CAMetalLayer wantsExtendedDynamicRangeContent be considered deprecated? Some links for context: CAMetalLayer wantsExtendedDynamicRangeContent for iOS 16+ CALayer wantsExtendedDynamicRangeContent for iOS 17+ CALayer preferredDynamicRange for iOS 26+ So Metal got it, then CALayer got it, then CALayer got a more extensible one in iOS26 and wantsExtendedDynamicRangeContent got marked Deprecated. But it's not marked as deprecated on the CAMetalLayer. I tested it and setting preferredDynamicRange on the CALayer worked to allow my CAMetalLayer to show HDR content on both iOS 27 and tvOS 27. I don't know if there's some reason though (performance for example?) to prefer setting the property on the CAMetalLayer rather than the CALayer. I'm asking because I want react-native-webgpu to support HDR on tvOS, but right now they're using CAMetalLayer wantsExtendedDynamicRangeContent which has no tvOS support. https://github.com/wcandillon/react-native-webgpu/pull/607
0
0
10
16m
Total triangle budget for a one skinned character app, iOS 26 and later
Hello, I’m working on an iOS app built around a single skinned character with fur, rendered in Metal and shown in close-up, so it takes up most of the screen. It needs to run at a steady 60fps, and the oldest hardware I want to support is the A15 (iPhone 13). The fur will be alpha cards layered over the base mesh. All of the character’s motion is computed on the GPU each frame, and ARKit and Vision hand tracking are running at the same time. This is what I have so far. A 180k-triangle test character with no hair cards runs smoothly in the Simulator on my Mac (yes, I know it's not entirely representative of the GPU numbers on a phone). On an actual iPhone 16, a synthetic bench (60k vertices, 4 influences each) put GPU skinning at 1.1 to 1.3 ms whether I used 250 joints or 1000, so I’m not worried about skinning. The final model is still being built, so I can’t test the real thing yet, but I have to give the modeler a budget now. I’m thinking of 100k to 120k triangles in total, base mesh plus alpha cards. Would that look fairly reasonable for an A15, or not? Thanks!
0
0
137
11h
A small scrolling ticker pins GPU at ~50% on a rich screen but ~0% on a blank one — is whole-tree compositing at the animation's rate the expected cost?
I have a SwiftUI clock-radio app on iPhone (ProMotion display). The face is a rich, layered screen (glass panels, gradients, shadows). One element is a 340×46 pt text ticker strip that scrolls continuously. Its GPU behaviour is reproducible and, to me, surprising: Measurements (Xcode GPU gauge used only for within-session relative contrasts; cadence from an in-app frame-pacing log): With the ticker scrolling, GPU sits at a ~50% plateau. The step is binary: one scroller or three scrollers cost the same. Frames are never dropped: 16.7 ms median frame time, ~3% of frames over 20 ms. The GPU bills heavily for frames it renders on time. The same strip scrolling on an otherwise blank screen costs ~0%. The ticker visible but static costs 0%. Motion is the trigger; the cost scales with what surrounds the strip, not with the strip itself. What I have tried: SwiftUI offset animation of the text — baseline behaviour above. A fully severed Canvas leaf: own layer subtree, own CADisplayLink, snapshot-fed, no view-tree publishing or subscriptions — identical cost on the full face (and literally 0% redrawing alone on a blank screen at full frame rate). Pre-rendered bitmap content scrolled instead of text — identical. The strip hosted in a separate UIWindow above the face — identical, measured with the strip visibly scrolling in its seat. Pinning the strip's CADisplayLink.preferredFrameRateRange to exactly 30 Hz (minimum = maximum = preferred = 30) — no change. .compositingGroup() on the panel subtree — a modest reduction only. What works: removing the motion duty (scroll once, then park — cost collapses), and, elsewhere in the app, a pull-model spectrum visualiser replaced a publish-driven one and its cost vanished. Severing worked for the visualiser but not for the ticker. Questions: Is this step the expected consequence of the WWDC22 session 10083 rule (the display refresh rate is set by the highest-frame-rate animation in the app) composed with whole-layer-tree compositing per presented frame? Is there any dirty-region scoping that a layer structure like ours defeats? The 30 Hz pin above was hard (min = max = preferred). Would a CAFrameRateRange in the 15–24 Hz band that Apple's ProMotion guidance suggests for small, slow animations behave materially differently, or is that distinction already settled by the 30 Hz result? Is there a known construction for a continuously scrolling ticker that lets the GPU idle between updates? Happy to share a minimal repro or the pacing logs if useful.
2
0
466
1d
Distributing D3DMetal with a Mac App Store app
Hello, We develop a Mac App Store app that runs Windows on Apple silicon. We use D3DMetal from the Game Porting Toolkit so that DirectX 12 games and apps can run in it. Today, each user has to download the Game Porting Toolkit, open the "Evaluation environment" disk image and point our app to D3DMetal.framework. Many users find this confusing, and we would like to make DirectX 12 work out of the box. When we tried to bundle D3DMetal.framework in our app, App Store Connect rejected the upload: ▎ Invalid Bundle. The application bundle may not contain tools or frameworks provided by Apple, or using bundle identifiers in the 'com.apple.' namespace. Invalid bundle: D3DMetal … with bundle identifier 'com.apple.D3DMetal'. We also note that the Game Porting Toolkit licence limits distribution to non-commercial purposes. Our questions: Is there an approved way for a Mac App Store app to include or distribute D3DMetal, for example a commercial redistribution agreement or a separate licence? If not, is there a supported way for an App Store app to obtain D3DMetal on the user's Mac, such as an Apple-provided download or a system component it can use? Are there plans to make D3DMetal available to third-party apps, as a public framework or as part of macOS? We want to follow Apple's licence and App Store guidelines, so any guidance on the correct approach would be much appreciated. Thank you.
0
0
132
2d
CIRAWFilter.supportedCameraModels(with: .version9) does not include camera models that appear to be supported
CIRAWFilter.supportedCameraModels(with: .version9) does not include some camera models that appear to be supported. For example a Sony A1 or Nikon Z8 RAW file opened using CIRAWFilter and then calling filter.supportedDecoderVersions.contains(.version9) return true but these models are not included in the supportedCameraModels list. Why is the supportedCameraModels(with:) not all the supported camera models ?
0
0
139
2d
Metal 4: MTL4Compiler crashes when many threads capture binaries into one MTL4PipelineDataSetSerializer
Hey all, hoping someone on the Metal team can take a look at this one. It's a crash inside Metal 4's binary capture, and as far as I can tell there's no way to fix it from the app side. Filed as FB25478288 (partial repro is link is there too). Why I think it matters The setup that crashes is basically the recommended Metal 4 workflow: one MTL4Compiler with a MTL4PipelineDataSetSerializer (CaptureBinaries) attached, called from maximumConcurrentCompilationTaskCount threads, to harvest pipelines for an offline archive. Lots of pipelines share a vertex function, which I'd guess is true for most real renderers. The crash is 100% inside Metal.framework, with no app code on the crashing thread. It's easy to hit: 3 out of 3 harvest runs crashed for us, one of them 2 s in. The serializer is attached to the compiler implicitly, so the app can't put a lock around whatever it does internally. MTL4Compiler is Sendable, and the docs say it handles multithreading by default, so I'd expect capture to be thread-safe too. Environment MacBook Pro M2 Max, macOS 27.2, Xcode 27.2, Metal toolchain 32023.922.4 Also reported on an M3 Pro ~33k render pipelines over ~16k vertex functions, up to ~1,000 pipelines in a row sharing one vertex function MTL4RenderPipelineDescriptor with MTL4LibraryFunctionDescriptor stages (sometimes wrapped in MTL4SpecializedFunctionDescriptor), all colour attachments Unspecialized The serializer gets written out with serializeAsArchiveAndFlushToURL: every so often, then we start a fresh compiler + serializer Crash EXC_BAD_ACCESS (SIGSEGV), "possible pointer authentication failure": objc_msgSend MultiLevelAirntBinaryCache::getElementAtDestination(MTLBinaryKey*, ...) -[MTLCompiler compileFunctionRequestInternal:frameworkLinking:linkDataSize:reflectionOnly:compilerTask:completionHandler:] ... AGX::Compiler::compileProgram<AGX::VertexProgramKey, ...>It looks like a use-after-free: two compiles capturing the same vertex program at the same time, and an entry in the destination archive gets freed while the other one is still using it. It only happens with capture on, and it goes away if we never let two capture compiles that share a stage function run at once. Workaround we ship (not great) A lock per stage function around each capture compile, plus sending runs of pipelines that share a vertex shader to the same thread. That stopped the crashes, but we had to put a timeout on the lock, because the compiler occasionally never returns, so in theory it can still race. Second, related crash If serializeAsArchiveAndFlushToURL: runs while other threads are still compiling into that serializer, we get a different crash (null deref at 0x30) in dispatch_data_create_map ← -[_MTLBinaryArchive newArchiverIdWithBinaryKey:entry:srcArchiverId:functionType:]. Our standalone repro hits this one reliably. The getElementAtDestination crash only shows up with our real workload so far. Repro + details https://github.com/Aeonitis/metal4-capture-race It's a small Objective-C repro (Metal + Foundation only) with a bunch of modes, the results so far, and a comparison with how Vulkan (VkPipelineCache) and D3D12 spell out the thread-safety rules for this same pattern. Questions Is capturing from multiple threads into one MTL4PipelineDataSetSerializer meant to be supported? If not, could the docs say so? Is one compiler + one serializer per thread a safe workaround, or is there shared state between compilers in the same process that would still race? Is calling serializeAsArchiveAndFlushToURL: while compiles are still in flight on that serializer allowed? Is this already fixed in a seed
0
0
304
3d
Request for PROLED display to support Adaptive Sync (VRR)
I was hoping with an OLED display that the new MBP might support true Adaptive Sync aka VRR. Alas, it only gets ProMotion, with the same huge gap between supported refresh rates at the top end (60hz and 120hz). Hooking up an HDMI VRR display such as any LG TV results in a display that works much better with variable framerates than the built-in display, since you can deliver frames at any interval between the min and max. VRR greatly improves games and already works great in macOS with an external display, so I humbly request that Apple consider another option next to ProMotion, for Adaptive Sync/VRR.
0
0
206
3d
Game Center Player Identity Continuity After App Transfer Between Developer Accounts
Dear Apple Developer Support Team, We plan to transfer multiple non-Apple Arcade games from Developer Account A to Developer Account B. The transfers have not yet been initiated. Approximately one million existing players use Game Center to sign in and link their identities to our in-game accounts. Before initiating the transfers, we need to clarify how player identities will be preserved. If internal implementation details cannot be disclosed, please describe the observable behavior from our apps and backend servers. We would appreciate direct confirmation or correction of the following statements. Background We use Game Center authentication signatures to verify player identities and associate Game Center IDs with our own account system, following Apple’s requirement: “Trust only the fields in the signed payload.” Our existing records contain legacy playerID (deprecated API) and teamPlayerID, but not gamePlayerID. Apple documentation states that the current authentication signature payload for non-Arcade games contains teamPlayerID, bundleID, timestamp, and salt, but not gamePlayerID. Therefore, even if gamePlayerID remains unchanged after the transfer, we cannot independently verify its authenticity. After the transfer, there will be three player categories: Existing installations that are not updated, continuing to use versions signed by Account A. New installations downloaded from the App Store after the transfer, still using versions signed by Account A. Players who update to new versions released under Account B. Questions 1. legacy playerID: Status and Availability (A) Is playerID globally scoped rather than tied to a developer account (Team ID)? Does transferring an app leave existing players’ playerID values unchanged? (B) Does Apple provide any way to map historically stored legacy playerID values to the corresponding gamePlayerID or teamPlayerID? (C) Although the playerID API is deprecated, will Apple stop returning this value in a future iOS version, or under any specific conditions? 2. What Determines teamPlayerID? Please confirm which model applies, or explain the actual mechanism: (A) teamPlayerID is determined by the app’s current developer account (Team ID), meaning all players’ values change immediately when the transfer takes effect, regardless of app version. (B) teamPlayerID is determined by the account that signed the installed app, meaning values change individually when players update to a version signed by Account B. For the three player categories above, which account’s teamPlayerID will Game Center return? Specifically: Will categories (1) and (2) receive the same value? Are there differences between app updates, fresh installations, and uninstalling and reinstalling? 3. Can Older Versions Signed by Account A Still Be Verified? (A) Can older versions in categories (1) and (2) still authenticate with Game Center and generate valid signatures that our backend can verify? (B) Will Apple stop issuing authentication signatures for versions signed by Account A? If so, under what conditions or after what period? 4. How Can Players Be Reliably Reassociated with Their Original Game Accounts? If teamPlayerID changes after the transfer, while gamePlayerID remains unchanged but is absent from the signed payload: (A) Does Apple provide an official mechanism to prove that a post-transfer player identifier belongs to the same Game Center account as a previously stored identifier? (B) If not, how does Apple recommend that non-Arcade games securely verify that returning players are the legitimate owners of their original game accounts after an account transfer? (C) If Apple recommends using gamePlayerID, please clarify: Is accepting a client-reported gamePlayerID, which is not included in the signed payload, an Apple-approved practice for non-Arcade games? Since an attacker could submit another player’s gamePlayerID to hijack their account, what protection does Apple recommend against such impersonation? 5. Required Actions and Timing for Developers and Players (A) What actions should Accounts A and B take at each stage of the transfer? Does Apple provide migration credentials, identifier mapping exports, or other migration mechanisms? (B) Must players sign in or update the app before the transfer takes effect? What happens to those who do not? (C) If players must act within a specific time window, how should we handle those who do not launch the game during that period and only return months or years later? How can their original accounts and game data be preserved? 6. Can We Verify These Behaviors Before the Transfer? (A) Can Game Center Sandbox or TestFlight environments reproduce identifier changes before and after an app transfer between developer accounts? (B) If not, can we transfer a test app between our two developer accounts to verify the actual behavior? Are there any restrictions? (C) If neither approach is possible, what does Apple recommend for verifying these behaviors before the actual transfer? ⸻ This transfer affects the continuity of approximately one million existing player accounts. We would therefore like to obtain clarification before submitting the transfer requests. If these questions are outside the current support team’s scope, please escalate this inquiry to the Game Center engineering team. Thank you for your assistance. Best regards !
0
0
48
5d
PDFKit Page Rerender
I'm experiencing an issue with PDFKit where page.removeAnnotation(annotation) successfully removes the annotation from the page's data structure, but the PDFView no longer updates automatically to reflect the change visually. Issue Details: The annotation is removed (verified by checking page.annotations.count) The PDFView display doesn't refresh to show the removal This code was working correctly before and suddenly stopped working No code changes were made on my end
5
3
1.9k
5d
Request for higher hardware encoding resolution/performance on the future Mac desktop/laptop platforms for VR support.
Request: Mac media-engine headroom for 3840-per-eye stereo encoding to Apple Vision Pro We develop a Mac app that streams OpenXR VR applications, rendered on the Mac's GPU, to Apple Vision Pro as stereo video. The Mac encodes with VideoToolbox, as MV-HEVC (one layer per eye) or side-by-side HEVC. Vision Pro decodes the stream and presents it in an immersive space. We'd like to ask for future Mac hardware to support stereo encoding at Vision Pro-class resolution: 3840 pixels per eye at 90 fps. Why resolution matters without eye tracking Vision Pro does not give applications eye-tracking data. We understand and respect the privacy reasons. It does mean a streaming app can not use gaze-driven foveated encoding, which sends full detail where the wearer is looking and less elsewhere. Streaming solutions on other headsets use that to stay within their encoder budget. Without gaze data, every part of each eye's image has to be sent at full detail, so the only route to a sharper image is encoding more pixels. Today the encoder is where that stops. What we measured (tested on an M4 Max) M4 Max, macOS 27.0.1, hardware HEVC through VideoToolbox, synthetic frames at 200 Mbps, no frame reordering, RealTime off, speed prioritised, frames submitted at 90 Hz with at most 4 in flight, eye heights at 20:19. Results are frames per second, with median encode latency in brackets. MV-HEVC: 2048×1952 per eye: 90 fps (16 ms) 2240×2128 per eye: 90 fps (19 ms), the largest size that holds 90 2304×2192 per eye: 87 fps (46 ms) 3072×2928 per eye: 50 fps (79 ms) 3840×3648 per eye: 33 fps (121 ms) Side-by-side HEVC: 2048×1952 per eye: 90 fps (12 ms) 3072×2928 per eye: 90 fps (25 ms) 3200×3040 per eye: 90 fps (27 ms), the largest size that holds 90 3328×3168 per eye: 86 fps (46 ms) 3840×3648 per eye: 65 fps (61 ms) What the numbers show: One MV-HEVC session uses one media engine (about 0.92 Gpx/s at every size). The second engine sits idle: two MV-HEVC sessions at 3840 per eye run at the same time at 33 fps each. One single-layer HEVC session spreads across both engines (about 1.82 Gpx/s), but only while nothing else is encoding. With a second session open (we used a 1080p30 desktop share), it drops to one engine: 3072 per eye falls from 90 to 52 fps, and 3840 per eye from 65 to 33 fps. GPU load does not slow the media engine. We repeated the tests beside a synthetic GPU load using 7 to 9.6 ms of every 11.1 ms frame, as a VR title would, and every result was unchanged. The encoding window we actually have At 90 Hz a frame lasts 11.1 ms, and the VR application uses most of that rendering on the GPU. Rendering and encoding run in sequence for each frame, so every millisecond of encoding adds directly to the wearer's motion-to-photon latency, on top of the app's own frame. In practice we need two things from the encoder: Latency: finish each frame within about one frame period (around 11 ms), so the stream adds no more than one frame beyond the app. Today 2048 per eye MV-HEVC takes 16 ms, or about 1.5 frames. Headroom: run at no more than about 75 % of capacity. Real scenes vary in complexity, and near the limit latency climbs steeply (side-by-side HEVC goes from 27 ms at 3200 per eye to 46 ms at 3328 per eye). At 75 % load an M4 Max supports about 2000 per eye for MV-HEVC, which is the 2048 we ship today, and about 2800 per eye for side-by-side HEVC when no other session is running. 3840×3648 per eye at 90 fps is 2.52 Gpx/s. With the 25 % headroom, that is about 3.4 Gpx/s of sustained encode capacity: roughly 1.9× both M4 Max engines together, or 3.7× the single engine an MV-HEVC session gets today. For comparison, our Windows host encodes MV-HEVC at 3840×3648 per eye at 90 fps on a current desktop NVIDIA GPU, in about 11 ms per frame, by splitting the work across its encoder engines. Vision Pro decodes and presents that stream at 90 fps, so the headset handles this resolution. The gap is on the Mac's encoding side. What we don't know yet We do not yet know whether the Mac GPU can render VR titles at 3840 per eye at 90 fps; that will depend on the title. We can not usefully find out while the encoder limits us first, so in practice we ship MV-HEVC/HEVC at 2048 per eye by default. What we're asking for About 3.4 Gpx/s of HEVC / MV-HEVC encode capacity in future Mac media engines, enough for 3840×3648 per eye at 90 fps with headroom, plus room for a smaller second session such as a desktop share. MV-HEVC/HEVC sessions that can use more than one media engine on chips that have them. On current chips this alone would roughly double the stereo ceiling. A single-layer HEVC session that keeps its multi-engine split while another session is running, or a property to request that. If the platform can offer it, a privacy-preserving foveation path for streaming apps, where the system supplies a foveation region to the encoder without the app ever seeing raw gaze. If a VideoToolbox configuration already lets one MV-HEVC/HEVC session use both engines, we'd be glad to hear about it. We're happy to file a Feedback report with our test tool attached.
0
0
204
5d
Damage numbers on 100s of enemies - performance question
Hello guys, i hope someone can help with that *i already have particle system working for hit feedback on enemies, and i manage to maintain the FPS quite good while using a pre-wamred pool of emitters and a cleanup system that cycle thru that pool. So i do have some basic experience with the particle system and the ECS system. For the spawning of damage numbers of enemies, I try to find a way to show damage numbers on enemies while keeping performence . 100s of enemies might get hit at a single frame, In unreal i used niagara Particles with UV pooling, with mass. object pooling the numbers with the GPU itself fed by the cpu mass ECS. What is the best way to do that in reality kit ? System is very high level, im not sure what is the best approach to begin with to keep good FPS. even if i need to use AI to write some custom shader, i still need help to design the overall system (should i put the logic inside an ECS system with a dedicated emitter with a custom metal shader for the particles?) Thank you guys
1
0
851
5d
All GameKit loadImage calls fail.
Everything I have seems to match what App Store Connect wants, image wise, and app store connect shows what looks good. Achievements and leadboards show on the devices (Mac, and iOS), but without images. I'm hoping it's not because they are in a prerelease state because I'd hate to have to release the app under the assumption they will show when I can't verify it locally. (Testing in production, essentially). When they didn't show in the overlay or gamecenter app, I put code in to dump the state of things, which is where the image errors are thrown. Leaderboard: Error Domain=GKErrorDomain Code=3 "The requested operation could not be completed due to an error communicating with the server." UserInfo={NSLocalizedDescription=The requested operation could not be completed due to an error communicating with the server.} Achivement: Error Domain=GKErrorDomain Code=1 "(null) Notes: Turning on debug mode turns all loads into code 3. Every device I try this on has the problem. The user is logged in properly based on a dump of the GKLocalPlayer instance. I can't seem to get debug mode to work on Mac, or I don't understand it. I was hoping that enabling that would default to pulling images from the app bundle. (The gamekit bundle-ish folder is included in the app) I've replaced all images locally and remotely using Xcode and using the web page to rule them out. I made sure there's no transparency in the images. It seems, but I don't know for sure, that that could cause load issues. I don't see any errors showing up use the Console app. Only my diagnostic report gives me an indication as to why there are no images. I'm considering removing all achievements and leaderboards, which I think would be unfortunate, but I don't want empty images, and I'm frustrated.
0
0
33
5d
WebGL linkProgram fails for every program in a Mac Catalyst WKWebView on macOS 27.3 beta
On macOS 27.3 beta (26C5035r), WebGL draws nothing in a WKWebView in a Mac Catalyst app. A WebGL2 context is created and shaders pass COMPILE_STATUS, but linkProgram fails for every program, with LINK_STATUS false and an empty program log. The same source file draws when built for My Mac. The same page also draws in Safari 27.3 and in the iOS 27.0 Simulator. Only the Mac Catalyst build fails. To reproduce, run a trivial vertex and fragment shader pair in a WKWebView, built for My Mac (Mac Catalyst): LINK_STATUS: false program log: "" pixel: 0, 0, 0, 0 getError: 1282 The unified log for the Catalyst app's com.apple.WebKit.GPU process shows this for each shader: (Metal) Metal Compiling Shader (Metal) Compiler failed to build request MTLCompilerService logs "Compilation BEGIN" for each request, then no "Compilation SUCCESS". The Metal source from WEBGL_debug_shaders is byte-identical in the Mac and Catalyst views, and with ANGLE's link placeholders filled in by hand it compiles in a Catalyst process, so the failure seems specific to the Catalyst GPU process. Signing, app sandbox, hardened runtime and a new bundle identifier make no difference. A macOS bundle loaded into the Catalyst process does not help, because its WKWebView is the Catalyst one. Sketchy Workaround: run the page in an AppKit WKWebView in a separate macOS helper process. FB25444425
0
0
61
6d
Get Desktop background image
In a WWDC 2019 "Advances in macOS Security" at 18:40 there is the following code func getDesktopWindowIds() -> [CGWindowID] { let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID)! as! [[String: AnyObject]] let DesktopWindowLevel = CGWindowLevelForKey(.desktopWindow)-1 let DesktopWindows = windows.filter { let windowLevel = $0[kCGWindowLayer as String] as! CGWindowLevel return windowLevel == desktopWindowLevel } return desktopWindows.map { $0[kCGWindowNumber as String] as! CGWindowID } } to find the CGWindowID of the Desktop background. This works, but when you then try to get the CGImage for that CGWindowID with let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.bestResolution]) cgImage does get a reference, however it's just a gray image. Not the Desktop picture. It's clear from the documentation that ScreenCaptureKit should be used. However, if used I get multiple warnings to the user, the most concerning one states: "App" would like to record this computer's screen and audio. This is not true! I do nothing with audio and to say a capture is a recording is also misleading. Is there way to achieve what use to work before macOS 27? Or a way to change/avoid this misleading warning? Is there a reason why this warning is needed for capturing the Desktop background where before it was explicitly allowed?
7
0
3.3k
6d
Separate CGBitmapContexts drawn concurrently produce wrong pixels when another thread fills translucent shapes (FB25211753)
Hi, my first post :-) feel free to say hi! I’ve filed this as FB25211753 and am posting in case others hit it. When several threads each draw into their own CGBitmapContext (separate buffers, separate contexts), one context’s output is corrupted if another thread is filling translucent shapes at the same time. QA1238 says drawing to separate Quartz objects on separate threads is supported. With only identical renders running concurrently, 0 of 64 differ from a serial reference. With another thread filling translucent ellipses into an unrelated context, 32 of 32 differ. On macOS 27.0.1, each corrupted render has about 0.3–4.6% of its bytes wrong, by up to 219 of 255 levels. On 26.5.1 it was smaller: 0.2–0.5%, up to 55. It’s triggered by translucent ellipses or paths. Opaque fills and translucent rectangles don’t trigger it, and per-thread colour spaces don’t help. Thread Sanitizer reports no race in the test code. Configuration: MacBook Pro (M4 Pro), macOS 26.5.1 and 27.0.1, Xcode 26.4 / Swift 6.3. Minimal reproduction (Core Graphics only). Run with swiftc -O repro.swift -o repro && ./repro: // Separate CGBitmapContexts drawn on separate threads give wrong pixels while another thread fills translucent // shapes. Seen on macOS 26.5.1 and 27.0.1 (Apple M4 Pro). Core Graphics only. // Run: swiftc -O repro.swift -o repro && ./repro // Minimal repro: separate CGBitmapContexts on separate threads, Core Graphics only. import CoreGraphics import Foundation let sRGB = CGColorSpace(name: CGColorSpace.sRGB)! /// A fixed drawing: black, a few large translucent ellipses and a stroked circle. func victim() -> [UInt8] { let w = 600, h = 400 let ctx = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: w * 4, space: sRGB, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)! ctx.setFillColor(CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1)) ctx.fill(CGRect(x: 0, y: 0, width: w, height: h)) for i in 0..<6 { ctx.setFillColor(CGColor(srgbRed: 1, green: Double(i) / 6, blue: 0.3, alpha: 0.5)) ctx.fillEllipse(in: CGRect(x: 40 + i * 80, y: 100, width: 120, height: 120)) } ctx.setStrokeColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 0.3)) ctx.strokeEllipse(in: CGRect(x: 100, y: 50, width: 400, height: 300)) let p = ctx.data!.assumingMemoryBound(to: UInt8.self) return Array(UnsafeBufferPointer(start: p, count: w * h * 4)) // read the context's own memory: no image decoding } /// Unrelated work on another context: many tiny translucent ellipses. func aggressor() { let ctx = CGContext(data: nil, width: 800, height: 500, bitsPerComponent: 8, bytesPerRow: 0, space: sRGB, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)! for k in 0..<1600 { ctx.setFillColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: Double(k % 7) / 7)) ctx.fillEllipse(in: CGRect(x: k % 800, y: k % 500, width: 1, height: 1)) } } let reference = victim() for mode in ["victims only", "victims + aggressors"] { let lock = NSLock() nonisolated(unsafe) var bad = 0, compared = 0 DispatchQueue.concurrentPerform(iterations: 64) { i in if mode != "victims only", i % 2 == 1 { aggressor(); return } let same = victim() == reference lock.lock(); compared += 1; if !same { bad += 1 }; lock.unlock() } print("\(mode): \(bad) of \(compared) renders differ from the serial reference") } Has anyone else seen this, or found a workaround other than drawing on a single thread?
5
0
1.9k
6d
D3DMetal: present hangs permanently when the game window becomes occluded
Environment macOS 27.0.1 (26A434), Apple M4 Pro Apple Game Porting Toolkit 4.0b2 (D3DMetal.framework) via CrossOver 27 D3D12 game, borderless fullscreen window (2540x1650) Symptom When the game window becomes occluded — Mission Control, a system OSD (volume/brightness), or another window being brought to the front — the game never renders another frame. It does not crash: GPU utilization drops to 0%, the process stays alive with near-zero CPU, and it never recovers. Killing and restarting the game is the only way out. D3DMetal log at the moment it happens: [D3DMetal:FATAL:%llX][%s:%d] Failed to get drawable for HWND. Run with D3DM_NO_WINDOW=1 env. Question When CAMetalLayer/nextDrawable has no drawable (window not visible), is there a supported way for D3DMetal to skip frames instead of blocking forever? Is there an environment variable or configuration that makes D3DMetal treat "no drawable" as a recoverable condition? Does D3DM_NO_WINDOW=1 apply here, or is it only for headless/offscreen use? I understand apps should handle a nil drawable and continue, but this path is inside D3DMetal. Any guidance would help.
3
0
1.2k
6d
How to spin every cell of a 7×7 and 12×12 without one SCNView per cell
We render a grid of small USDZ models in SceneKit, one model per cell, and each model should spin continuously around its own local Y axis (one full turn every ~8 seconds). Simple grids of 7 and 12 cells work. A full 7×7 (49) or 12×12 (144) does not. Today each spinning cell is its own SCNView with rendersContinuously = true and an SCNAction.rotateBy on that cell’s pivot node. On macOS, opening a 7×7 of these views deadlocks SceneKit: layout stalls inside setFrameSize / setBackgroundColor while every render thread waits on the shared irradiance lock. We cap live views at 12 and keep the remaining cells as static bitmap snapshots, mounted in waves of four. Frame rate is already tiered (12 / 24 / 30 fps) and antialiasing is reduced on weaker devices. The same grid runs on macOS, iPad, and iPhone. What is the efficient way to spin every cell of a 7×7 and a 12×12 around its own axis? Specifically: one shared SCNScene (or one MTKView plus SCNRenderer) with many nodes, each rotating locally, instead of one SCNView per cell — and how should we share geometry, avoid per-view render loops, and stay off that irradiance lock during layout?
2
0
1.3k
1w
GameSaveSyncedDirectory.openDirectory() crashes in CloudDocs initUIApplicationWillResignActiveNotification
We use the GameSave framework to sync player save data to iCloud. Since iOS 27, our game crashes a few seconds after a cold launch, the first time it calls GameSaveSyncedDirectory.openDirectory(). We call the API only from the main actor, but the crash is on a cooperative thread inside GameSave: EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x400000000000bad0 libobjc.A.dylib objc_release CloudDocs initUIApplicationWillResignActiveNotification CloudDocs -[BRQuery _setQueryState:] CloudDocs -[BRQuery _runQuery] CloudDocs -[BRQuery executeWithOptions:] Foundation -[NSMetadataQuery startQuery] GameSave BundleUpdatesWaiter.initMetadataQuery() GameSave BundleUpdatesWaiter.init(bundleURL:) GameSave closure #1 in GameSyncedDirectoryHolder.allowReaders(for:)Other threads are inside the same BRQuery path at the same moment. The crash reproduces without GameSave: starting twoNSMetadataQuery objects at once on background threads in a fresh process crashes 94 times in 100 in the iOS 27.0 Simulator, and never on iOS 26.5, so this seems like a regression. Starting one query on a single thread never crashes. I've submitted a support request (FB25352978) so hopefully this will be looked at fairly soon - if anyone else runs into this it would be good to know!
3
0
640
1w
CGSetDisplayTransferByTable is broken on macOS Tahoe 26.4 RC (and 26.3.1) with MacBook M5 Pro, Max and Neo
The CGSetDisplayTransferByTable() is not working on the latest round of Mac hardware, namely the MacBook Neo (external display), MacBook M5 Pro (both built-in and external display) and possibly the M5 Max. All tested apps (BetterDisplay, MonitorControl, f.lux, Lunar) exhibit the very issue both in macOS Tahoe 26.3 and macOS Tahoe 26.4 RC. Tested on multiple Macs and installations on the MacBook Neo and MacBook M5 Pro. This issue breaks several display related macOS apps. Way to reproduce the issue using an affected app: Install the app BetterDisplay (https://betterdisplay.pro) Launch the app, open the app menu, choose Image Adjustments and try to adjust colors. Adjustments take no effect Way to reproduce the issue programmatically: Attempt to use the affected macOS API feature: https://developer.apple.com/documentation/coregraphics/cgsetdisplaytransferbytable(::::_:) Here are the FB numbers: FB22273730 (Filed this one as a developer on an unaffected MBP M3 Max) FB22273782 (Filed from an affected MBP M5 Pro running 26.4 RC, with debug info attached)
18
7
8.4k
1w
Doc bug? Any reason to use Metal's wantsExtendedDynamicRangeContent instead of CALayer preferredDynamicRange?
Should CAMetalLayer wantsExtendedDynamicRangeContent be considered deprecated? Some links for context: CAMetalLayer wantsExtendedDynamicRangeContent for iOS 16+ CALayer wantsExtendedDynamicRangeContent for iOS 17+ CALayer preferredDynamicRange for iOS 26+ So Metal got it, then CALayer got it, then CALayer got a more extensible one in iOS26 and wantsExtendedDynamicRangeContent got marked Deprecated. But it's not marked as deprecated on the CAMetalLayer. I tested it and setting preferredDynamicRange on the CALayer worked to allow my CAMetalLayer to show HDR content on both iOS 27 and tvOS 27. I don't know if there's some reason though (performance for example?) to prefer setting the property on the CAMetalLayer rather than the CALayer. I'm asking because I want react-native-webgpu to support HDR on tvOS, but right now they're using CAMetalLayer wantsExtendedDynamicRangeContent which has no tvOS support. https://github.com/wcandillon/react-native-webgpu/pull/607
Replies
0
Boosts
0
Views
10
Activity
16m
Total triangle budget for a one skinned character app, iOS 26 and later
Hello, I’m working on an iOS app built around a single skinned character with fur, rendered in Metal and shown in close-up, so it takes up most of the screen. It needs to run at a steady 60fps, and the oldest hardware I want to support is the A15 (iPhone 13). The fur will be alpha cards layered over the base mesh. All of the character’s motion is computed on the GPU each frame, and ARKit and Vision hand tracking are running at the same time. This is what I have so far. A 180k-triangle test character with no hair cards runs smoothly in the Simulator on my Mac (yes, I know it's not entirely representative of the GPU numbers on a phone). On an actual iPhone 16, a synthetic bench (60k vertices, 4 influences each) put GPU skinning at 1.1 to 1.3 ms whether I used 250 joints or 1000, so I’m not worried about skinning. The final model is still being built, so I can’t test the real thing yet, but I have to give the modeler a budget now. I’m thinking of 100k to 120k triangles in total, base mesh plus alpha cards. Would that look fairly reasonable for an A15, or not? Thanks!
Replies
0
Boosts
0
Views
137
Activity
11h
A small scrolling ticker pins GPU at ~50% on a rich screen but ~0% on a blank one — is whole-tree compositing at the animation's rate the expected cost?
I have a SwiftUI clock-radio app on iPhone (ProMotion display). The face is a rich, layered screen (glass panels, gradients, shadows). One element is a 340×46 pt text ticker strip that scrolls continuously. Its GPU behaviour is reproducible and, to me, surprising: Measurements (Xcode GPU gauge used only for within-session relative contrasts; cadence from an in-app frame-pacing log): With the ticker scrolling, GPU sits at a ~50% plateau. The step is binary: one scroller or three scrollers cost the same. Frames are never dropped: 16.7 ms median frame time, ~3% of frames over 20 ms. The GPU bills heavily for frames it renders on time. The same strip scrolling on an otherwise blank screen costs ~0%. The ticker visible but static costs 0%. Motion is the trigger; the cost scales with what surrounds the strip, not with the strip itself. What I have tried: SwiftUI offset animation of the text — baseline behaviour above. A fully severed Canvas leaf: own layer subtree, own CADisplayLink, snapshot-fed, no view-tree publishing or subscriptions — identical cost on the full face (and literally 0% redrawing alone on a blank screen at full frame rate). Pre-rendered bitmap content scrolled instead of text — identical. The strip hosted in a separate UIWindow above the face — identical, measured with the strip visibly scrolling in its seat. Pinning the strip's CADisplayLink.preferredFrameRateRange to exactly 30 Hz (minimum = maximum = preferred = 30) — no change. .compositingGroup() on the panel subtree — a modest reduction only. What works: removing the motion duty (scroll once, then park — cost collapses), and, elsewhere in the app, a pull-model spectrum visualiser replaced a publish-driven one and its cost vanished. Severing worked for the visualiser but not for the ticker. Questions: Is this step the expected consequence of the WWDC22 session 10083 rule (the display refresh rate is set by the highest-frame-rate animation in the app) composed with whole-layer-tree compositing per presented frame? Is there any dirty-region scoping that a layer structure like ours defeats? The 30 Hz pin above was hard (min = max = preferred). Would a CAFrameRateRange in the 15–24 Hz band that Apple's ProMotion guidance suggests for small, slow animations behave materially differently, or is that distinction already settled by the 30 Hz result? Is there a known construction for a continuously scrolling ticker that lets the GPU idle between updates? Happy to share a minimal repro or the pacing logs if useful.
Replies
2
Boosts
0
Views
466
Activity
1d
Distributing D3DMetal with a Mac App Store app
Hello, We develop a Mac App Store app that runs Windows on Apple silicon. We use D3DMetal from the Game Porting Toolkit so that DirectX 12 games and apps can run in it. Today, each user has to download the Game Porting Toolkit, open the "Evaluation environment" disk image and point our app to D3DMetal.framework. Many users find this confusing, and we would like to make DirectX 12 work out of the box. When we tried to bundle D3DMetal.framework in our app, App Store Connect rejected the upload: ▎ Invalid Bundle. The application bundle may not contain tools or frameworks provided by Apple, or using bundle identifiers in the 'com.apple.' namespace. Invalid bundle: D3DMetal … with bundle identifier 'com.apple.D3DMetal'. We also note that the Game Porting Toolkit licence limits distribution to non-commercial purposes. Our questions: Is there an approved way for a Mac App Store app to include or distribute D3DMetal, for example a commercial redistribution agreement or a separate licence? If not, is there a supported way for an App Store app to obtain D3DMetal on the user's Mac, such as an Apple-provided download or a system component it can use? Are there plans to make D3DMetal available to third-party apps, as a public framework or as part of macOS? We want to follow Apple's licence and App Store guidelines, so any guidance on the correct approach would be much appreciated. Thank you.
Replies
0
Boosts
0
Views
132
Activity
2d
CIRAWFilter.supportedCameraModels(with: .version9) does not include camera models that appear to be supported
CIRAWFilter.supportedCameraModels(with: .version9) does not include some camera models that appear to be supported. For example a Sony A1 or Nikon Z8 RAW file opened using CIRAWFilter and then calling filter.supportedDecoderVersions.contains(.version9) return true but these models are not included in the supportedCameraModels list. Why is the supportedCameraModels(with:) not all the supported camera models ?
Replies
0
Boosts
0
Views
139
Activity
2d
Metal 4: MTL4Compiler crashes when many threads capture binaries into one MTL4PipelineDataSetSerializer
Hey all, hoping someone on the Metal team can take a look at this one. It's a crash inside Metal 4's binary capture, and as far as I can tell there's no way to fix it from the app side. Filed as FB25478288 (partial repro is link is there too). Why I think it matters The setup that crashes is basically the recommended Metal 4 workflow: one MTL4Compiler with a MTL4PipelineDataSetSerializer (CaptureBinaries) attached, called from maximumConcurrentCompilationTaskCount threads, to harvest pipelines for an offline archive. Lots of pipelines share a vertex function, which I'd guess is true for most real renderers. The crash is 100% inside Metal.framework, with no app code on the crashing thread. It's easy to hit: 3 out of 3 harvest runs crashed for us, one of them 2 s in. The serializer is attached to the compiler implicitly, so the app can't put a lock around whatever it does internally. MTL4Compiler is Sendable, and the docs say it handles multithreading by default, so I'd expect capture to be thread-safe too. Environment MacBook Pro M2 Max, macOS 27.2, Xcode 27.2, Metal toolchain 32023.922.4 Also reported on an M3 Pro ~33k render pipelines over ~16k vertex functions, up to ~1,000 pipelines in a row sharing one vertex function MTL4RenderPipelineDescriptor with MTL4LibraryFunctionDescriptor stages (sometimes wrapped in MTL4SpecializedFunctionDescriptor), all colour attachments Unspecialized The serializer gets written out with serializeAsArchiveAndFlushToURL: every so often, then we start a fresh compiler + serializer Crash EXC_BAD_ACCESS (SIGSEGV), "possible pointer authentication failure": objc_msgSend MultiLevelAirntBinaryCache::getElementAtDestination(MTLBinaryKey*, ...) -[MTLCompiler compileFunctionRequestInternal:frameworkLinking:linkDataSize:reflectionOnly:compilerTask:completionHandler:] ... AGX::Compiler::compileProgram<AGX::VertexProgramKey, ...>It looks like a use-after-free: two compiles capturing the same vertex program at the same time, and an entry in the destination archive gets freed while the other one is still using it. It only happens with capture on, and it goes away if we never let two capture compiles that share a stage function run at once. Workaround we ship (not great) A lock per stage function around each capture compile, plus sending runs of pipelines that share a vertex shader to the same thread. That stopped the crashes, but we had to put a timeout on the lock, because the compiler occasionally never returns, so in theory it can still race. Second, related crash If serializeAsArchiveAndFlushToURL: runs while other threads are still compiling into that serializer, we get a different crash (null deref at 0x30) in dispatch_data_create_map ← -[_MTLBinaryArchive newArchiverIdWithBinaryKey:entry:srcArchiverId:functionType:]. Our standalone repro hits this one reliably. The getElementAtDestination crash only shows up with our real workload so far. Repro + details https://github.com/Aeonitis/metal4-capture-race It's a small Objective-C repro (Metal + Foundation only) with a bunch of modes, the results so far, and a comparison with how Vulkan (VkPipelineCache) and D3D12 spell out the thread-safety rules for this same pattern. Questions Is capturing from multiple threads into one MTL4PipelineDataSetSerializer meant to be supported? If not, could the docs say so? Is one compiler + one serializer per thread a safe workaround, or is there shared state between compilers in the same process that would still race? Is calling serializeAsArchiveAndFlushToURL: while compiles are still in flight on that serializer allowed? Is this already fixed in a seed
Replies
0
Boosts
0
Views
304
Activity
3d
Request for PROLED display to support Adaptive Sync (VRR)
I was hoping with an OLED display that the new MBP might support true Adaptive Sync aka VRR. Alas, it only gets ProMotion, with the same huge gap between supported refresh rates at the top end (60hz and 120hz). Hooking up an HDMI VRR display such as any LG TV results in a display that works much better with variable framerates than the built-in display, since you can deliver frames at any interval between the min and max. VRR greatly improves games and already works great in macOS with an external display, so I humbly request that Apple consider another option next to ProMotion, for Adaptive Sync/VRR.
Replies
0
Boosts
0
Views
206
Activity
3d
Game Center Player Identity Continuity After App Transfer Between Developer Accounts
Dear Apple Developer Support Team, We plan to transfer multiple non-Apple Arcade games from Developer Account A to Developer Account B. The transfers have not yet been initiated. Approximately one million existing players use Game Center to sign in and link their identities to our in-game accounts. Before initiating the transfers, we need to clarify how player identities will be preserved. If internal implementation details cannot be disclosed, please describe the observable behavior from our apps and backend servers. We would appreciate direct confirmation or correction of the following statements. Background We use Game Center authentication signatures to verify player identities and associate Game Center IDs with our own account system, following Apple’s requirement: “Trust only the fields in the signed payload.” Our existing records contain legacy playerID (deprecated API) and teamPlayerID, but not gamePlayerID. Apple documentation states that the current authentication signature payload for non-Arcade games contains teamPlayerID, bundleID, timestamp, and salt, but not gamePlayerID. Therefore, even if gamePlayerID remains unchanged after the transfer, we cannot independently verify its authenticity. After the transfer, there will be three player categories: Existing installations that are not updated, continuing to use versions signed by Account A. New installations downloaded from the App Store after the transfer, still using versions signed by Account A. Players who update to new versions released under Account B. Questions 1. legacy playerID: Status and Availability (A) Is playerID globally scoped rather than tied to a developer account (Team ID)? Does transferring an app leave existing players’ playerID values unchanged? (B) Does Apple provide any way to map historically stored legacy playerID values to the corresponding gamePlayerID or teamPlayerID? (C) Although the playerID API is deprecated, will Apple stop returning this value in a future iOS version, or under any specific conditions? 2. What Determines teamPlayerID? Please confirm which model applies, or explain the actual mechanism: (A) teamPlayerID is determined by the app’s current developer account (Team ID), meaning all players’ values change immediately when the transfer takes effect, regardless of app version. (B) teamPlayerID is determined by the account that signed the installed app, meaning values change individually when players update to a version signed by Account B. For the three player categories above, which account’s teamPlayerID will Game Center return? Specifically: Will categories (1) and (2) receive the same value? Are there differences between app updates, fresh installations, and uninstalling and reinstalling? 3. Can Older Versions Signed by Account A Still Be Verified? (A) Can older versions in categories (1) and (2) still authenticate with Game Center and generate valid signatures that our backend can verify? (B) Will Apple stop issuing authentication signatures for versions signed by Account A? If so, under what conditions or after what period? 4. How Can Players Be Reliably Reassociated with Their Original Game Accounts? If teamPlayerID changes after the transfer, while gamePlayerID remains unchanged but is absent from the signed payload: (A) Does Apple provide an official mechanism to prove that a post-transfer player identifier belongs to the same Game Center account as a previously stored identifier? (B) If not, how does Apple recommend that non-Arcade games securely verify that returning players are the legitimate owners of their original game accounts after an account transfer? (C) If Apple recommends using gamePlayerID, please clarify: Is accepting a client-reported gamePlayerID, which is not included in the signed payload, an Apple-approved practice for non-Arcade games? Since an attacker could submit another player’s gamePlayerID to hijack their account, what protection does Apple recommend against such impersonation? 5. Required Actions and Timing for Developers and Players (A) What actions should Accounts A and B take at each stage of the transfer? Does Apple provide migration credentials, identifier mapping exports, or other migration mechanisms? (B) Must players sign in or update the app before the transfer takes effect? What happens to those who do not? (C) If players must act within a specific time window, how should we handle those who do not launch the game during that period and only return months or years later? How can their original accounts and game data be preserved? 6. Can We Verify These Behaviors Before the Transfer? (A) Can Game Center Sandbox or TestFlight environments reproduce identifier changes before and after an app transfer between developer accounts? (B) If not, can we transfer a test app between our two developer accounts to verify the actual behavior? Are there any restrictions? (C) If neither approach is possible, what does Apple recommend for verifying these behaviors before the actual transfer? ⸻ This transfer affects the continuity of approximately one million existing player accounts. We would therefore like to obtain clarification before submitting the transfer requests. If these questions are outside the current support team’s scope, please escalate this inquiry to the Game Center engineering team. Thank you for your assistance. Best regards !
Replies
0
Boosts
0
Views
48
Activity
5d
PDFKit Page Rerender
I'm experiencing an issue with PDFKit where page.removeAnnotation(annotation) successfully removes the annotation from the page's data structure, but the PDFView no longer updates automatically to reflect the change visually. Issue Details: The annotation is removed (verified by checking page.annotations.count) The PDFView display doesn't refresh to show the removal This code was working correctly before and suddenly stopped working No code changes were made on my end
Replies
5
Boosts
3
Views
1.9k
Activity
5d
Request for higher hardware encoding resolution/performance on the future Mac desktop/laptop platforms for VR support.
Request: Mac media-engine headroom for 3840-per-eye stereo encoding to Apple Vision Pro We develop a Mac app that streams OpenXR VR applications, rendered on the Mac's GPU, to Apple Vision Pro as stereo video. The Mac encodes with VideoToolbox, as MV-HEVC (one layer per eye) or side-by-side HEVC. Vision Pro decodes the stream and presents it in an immersive space. We'd like to ask for future Mac hardware to support stereo encoding at Vision Pro-class resolution: 3840 pixels per eye at 90 fps. Why resolution matters without eye tracking Vision Pro does not give applications eye-tracking data. We understand and respect the privacy reasons. It does mean a streaming app can not use gaze-driven foveated encoding, which sends full detail where the wearer is looking and less elsewhere. Streaming solutions on other headsets use that to stay within their encoder budget. Without gaze data, every part of each eye's image has to be sent at full detail, so the only route to a sharper image is encoding more pixels. Today the encoder is where that stops. What we measured (tested on an M4 Max) M4 Max, macOS 27.0.1, hardware HEVC through VideoToolbox, synthetic frames at 200 Mbps, no frame reordering, RealTime off, speed prioritised, frames submitted at 90 Hz with at most 4 in flight, eye heights at 20:19. Results are frames per second, with median encode latency in brackets. MV-HEVC: 2048×1952 per eye: 90 fps (16 ms) 2240×2128 per eye: 90 fps (19 ms), the largest size that holds 90 2304×2192 per eye: 87 fps (46 ms) 3072×2928 per eye: 50 fps (79 ms) 3840×3648 per eye: 33 fps (121 ms) Side-by-side HEVC: 2048×1952 per eye: 90 fps (12 ms) 3072×2928 per eye: 90 fps (25 ms) 3200×3040 per eye: 90 fps (27 ms), the largest size that holds 90 3328×3168 per eye: 86 fps (46 ms) 3840×3648 per eye: 65 fps (61 ms) What the numbers show: One MV-HEVC session uses one media engine (about 0.92 Gpx/s at every size). The second engine sits idle: two MV-HEVC sessions at 3840 per eye run at the same time at 33 fps each. One single-layer HEVC session spreads across both engines (about 1.82 Gpx/s), but only while nothing else is encoding. With a second session open (we used a 1080p30 desktop share), it drops to one engine: 3072 per eye falls from 90 to 52 fps, and 3840 per eye from 65 to 33 fps. GPU load does not slow the media engine. We repeated the tests beside a synthetic GPU load using 7 to 9.6 ms of every 11.1 ms frame, as a VR title would, and every result was unchanged. The encoding window we actually have At 90 Hz a frame lasts 11.1 ms, and the VR application uses most of that rendering on the GPU. Rendering and encoding run in sequence for each frame, so every millisecond of encoding adds directly to the wearer's motion-to-photon latency, on top of the app's own frame. In practice we need two things from the encoder: Latency: finish each frame within about one frame period (around 11 ms), so the stream adds no more than one frame beyond the app. Today 2048 per eye MV-HEVC takes 16 ms, or about 1.5 frames. Headroom: run at no more than about 75 % of capacity. Real scenes vary in complexity, and near the limit latency climbs steeply (side-by-side HEVC goes from 27 ms at 3200 per eye to 46 ms at 3328 per eye). At 75 % load an M4 Max supports about 2000 per eye for MV-HEVC, which is the 2048 we ship today, and about 2800 per eye for side-by-side HEVC when no other session is running. 3840×3648 per eye at 90 fps is 2.52 Gpx/s. With the 25 % headroom, that is about 3.4 Gpx/s of sustained encode capacity: roughly 1.9× both M4 Max engines together, or 3.7× the single engine an MV-HEVC session gets today. For comparison, our Windows host encodes MV-HEVC at 3840×3648 per eye at 90 fps on a current desktop NVIDIA GPU, in about 11 ms per frame, by splitting the work across its encoder engines. Vision Pro decodes and presents that stream at 90 fps, so the headset handles this resolution. The gap is on the Mac's encoding side. What we don't know yet We do not yet know whether the Mac GPU can render VR titles at 3840 per eye at 90 fps; that will depend on the title. We can not usefully find out while the encoder limits us first, so in practice we ship MV-HEVC/HEVC at 2048 per eye by default. What we're asking for About 3.4 Gpx/s of HEVC / MV-HEVC encode capacity in future Mac media engines, enough for 3840×3648 per eye at 90 fps with headroom, plus room for a smaller second session such as a desktop share. MV-HEVC/HEVC sessions that can use more than one media engine on chips that have them. On current chips this alone would roughly double the stereo ceiling. A single-layer HEVC session that keeps its multi-engine split while another session is running, or a property to request that. If the platform can offer it, a privacy-preserving foveation path for streaming apps, where the system supplies a foveation region to the encoder without the app ever seeing raw gaze. If a VideoToolbox configuration already lets one MV-HEVC/HEVC session use both engines, we'd be glad to hear about it. We're happy to file a Feedback report with our test tool attached.
Replies
0
Boosts
0
Views
204
Activity
5d
Damage numbers on 100s of enemies - performance question
Hello guys, i hope someone can help with that *i already have particle system working for hit feedback on enemies, and i manage to maintain the FPS quite good while using a pre-wamred pool of emitters and a cleanup system that cycle thru that pool. So i do have some basic experience with the particle system and the ECS system. For the spawning of damage numbers of enemies, I try to find a way to show damage numbers on enemies while keeping performence . 100s of enemies might get hit at a single frame, In unreal i used niagara Particles with UV pooling, with mass. object pooling the numbers with the GPU itself fed by the cpu mass ECS. What is the best way to do that in reality kit ? System is very high level, im not sure what is the best approach to begin with to keep good FPS. even if i need to use AI to write some custom shader, i still need help to design the overall system (should i put the logic inside an ECS system with a dedicated emitter with a custom metal shader for the particles?) Thank you guys
Replies
1
Boosts
0
Views
851
Activity
5d
All GameKit loadImage calls fail.
Everything I have seems to match what App Store Connect wants, image wise, and app store connect shows what looks good. Achievements and leadboards show on the devices (Mac, and iOS), but without images. I'm hoping it's not because they are in a prerelease state because I'd hate to have to release the app under the assumption they will show when I can't verify it locally. (Testing in production, essentially). When they didn't show in the overlay or gamecenter app, I put code in to dump the state of things, which is where the image errors are thrown. Leaderboard: Error Domain=GKErrorDomain Code=3 "The requested operation could not be completed due to an error communicating with the server." UserInfo={NSLocalizedDescription=The requested operation could not be completed due to an error communicating with the server.} Achivement: Error Domain=GKErrorDomain Code=1 "(null) Notes: Turning on debug mode turns all loads into code 3. Every device I try this on has the problem. The user is logged in properly based on a dump of the GKLocalPlayer instance. I can't seem to get debug mode to work on Mac, or I don't understand it. I was hoping that enabling that would default to pulling images from the app bundle. (The gamekit bundle-ish folder is included in the app) I've replaced all images locally and remotely using Xcode and using the web page to rule them out. I made sure there's no transparency in the images. It seems, but I don't know for sure, that that could cause load issues. I don't see any errors showing up use the Console app. Only my diagnostic report gives me an indication as to why there are no images. I'm considering removing all achievements and leaderboards, which I think would be unfortunate, but I don't want empty images, and I'm frustrated.
Replies
0
Boosts
0
Views
33
Activity
5d
WebGL linkProgram fails for every program in a Mac Catalyst WKWebView on macOS 27.3 beta
On macOS 27.3 beta (26C5035r), WebGL draws nothing in a WKWebView in a Mac Catalyst app. A WebGL2 context is created and shaders pass COMPILE_STATUS, but linkProgram fails for every program, with LINK_STATUS false and an empty program log. The same source file draws when built for My Mac. The same page also draws in Safari 27.3 and in the iOS 27.0 Simulator. Only the Mac Catalyst build fails. To reproduce, run a trivial vertex and fragment shader pair in a WKWebView, built for My Mac (Mac Catalyst): LINK_STATUS: false program log: "" pixel: 0, 0, 0, 0 getError: 1282 The unified log for the Catalyst app's com.apple.WebKit.GPU process shows this for each shader: (Metal) Metal Compiling Shader (Metal) Compiler failed to build request MTLCompilerService logs "Compilation BEGIN" for each request, then no "Compilation SUCCESS". The Metal source from WEBGL_debug_shaders is byte-identical in the Mac and Catalyst views, and with ANGLE's link placeholders filled in by hand it compiles in a Catalyst process, so the failure seems specific to the Catalyst GPU process. Signing, app sandbox, hardened runtime and a new bundle identifier make no difference. A macOS bundle loaded into the Catalyst process does not help, because its WKWebView is the Catalyst one. Sketchy Workaround: run the page in an AppKit WKWebView in a separate macOS helper process. FB25444425
Replies
0
Boosts
0
Views
61
Activity
6d
Get Desktop background image
In a WWDC 2019 "Advances in macOS Security" at 18:40 there is the following code func getDesktopWindowIds() -> [CGWindowID] { let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID)! as! [[String: AnyObject]] let DesktopWindowLevel = CGWindowLevelForKey(.desktopWindow)-1 let DesktopWindows = windows.filter { let windowLevel = $0[kCGWindowLayer as String] as! CGWindowLevel return windowLevel == desktopWindowLevel } return desktopWindows.map { $0[kCGWindowNumber as String] as! CGWindowID } } to find the CGWindowID of the Desktop background. This works, but when you then try to get the CGImage for that CGWindowID with let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.bestResolution]) cgImage does get a reference, however it's just a gray image. Not the Desktop picture. It's clear from the documentation that ScreenCaptureKit should be used. However, if used I get multiple warnings to the user, the most concerning one states: "App" would like to record this computer's screen and audio. This is not true! I do nothing with audio and to say a capture is a recording is also misleading. Is there way to achieve what use to work before macOS 27? Or a way to change/avoid this misleading warning? Is there a reason why this warning is needed for capturing the Desktop background where before it was explicitly allowed?
Replies
7
Boosts
0
Views
3.3k
Activity
6d
Separate CGBitmapContexts drawn concurrently produce wrong pixels when another thread fills translucent shapes (FB25211753)
Hi, my first post :-) feel free to say hi! I’ve filed this as FB25211753 and am posting in case others hit it. When several threads each draw into their own CGBitmapContext (separate buffers, separate contexts), one context’s output is corrupted if another thread is filling translucent shapes at the same time. QA1238 says drawing to separate Quartz objects on separate threads is supported. With only identical renders running concurrently, 0 of 64 differ from a serial reference. With another thread filling translucent ellipses into an unrelated context, 32 of 32 differ. On macOS 27.0.1, each corrupted render has about 0.3–4.6% of its bytes wrong, by up to 219 of 255 levels. On 26.5.1 it was smaller: 0.2–0.5%, up to 55. It’s triggered by translucent ellipses or paths. Opaque fills and translucent rectangles don’t trigger it, and per-thread colour spaces don’t help. Thread Sanitizer reports no race in the test code. Configuration: MacBook Pro (M4 Pro), macOS 26.5.1 and 27.0.1, Xcode 26.4 / Swift 6.3. Minimal reproduction (Core Graphics only). Run with swiftc -O repro.swift -o repro && ./repro: // Separate CGBitmapContexts drawn on separate threads give wrong pixels while another thread fills translucent // shapes. Seen on macOS 26.5.1 and 27.0.1 (Apple M4 Pro). Core Graphics only. // Run: swiftc -O repro.swift -o repro && ./repro // Minimal repro: separate CGBitmapContexts on separate threads, Core Graphics only. import CoreGraphics import Foundation let sRGB = CGColorSpace(name: CGColorSpace.sRGB)! /// A fixed drawing: black, a few large translucent ellipses and a stroked circle. func victim() -> [UInt8] { let w = 600, h = 400 let ctx = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: w * 4, space: sRGB, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)! ctx.setFillColor(CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1)) ctx.fill(CGRect(x: 0, y: 0, width: w, height: h)) for i in 0..<6 { ctx.setFillColor(CGColor(srgbRed: 1, green: Double(i) / 6, blue: 0.3, alpha: 0.5)) ctx.fillEllipse(in: CGRect(x: 40 + i * 80, y: 100, width: 120, height: 120)) } ctx.setStrokeColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 0.3)) ctx.strokeEllipse(in: CGRect(x: 100, y: 50, width: 400, height: 300)) let p = ctx.data!.assumingMemoryBound(to: UInt8.self) return Array(UnsafeBufferPointer(start: p, count: w * h * 4)) // read the context's own memory: no image decoding } /// Unrelated work on another context: many tiny translucent ellipses. func aggressor() { let ctx = CGContext(data: nil, width: 800, height: 500, bitsPerComponent: 8, bytesPerRow: 0, space: sRGB, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)! for k in 0..<1600 { ctx.setFillColor(CGColor(srgbRed: 1, green: 1, blue: 1, alpha: Double(k % 7) / 7)) ctx.fillEllipse(in: CGRect(x: k % 800, y: k % 500, width: 1, height: 1)) } } let reference = victim() for mode in ["victims only", "victims + aggressors"] { let lock = NSLock() nonisolated(unsafe) var bad = 0, compared = 0 DispatchQueue.concurrentPerform(iterations: 64) { i in if mode != "victims only", i % 2 == 1 { aggressor(); return } let same = victim() == reference lock.lock(); compared += 1; if !same { bad += 1 }; lock.unlock() } print("\(mode): \(bad) of \(compared) renders differ from the serial reference") } Has anyone else seen this, or found a workaround other than drawing on a single thread?
Replies
5
Boosts
0
Views
1.9k
Activity
6d
D3DMetal: present hangs permanently when the game window becomes occluded
Environment macOS 27.0.1 (26A434), Apple M4 Pro Apple Game Porting Toolkit 4.0b2 (D3DMetal.framework) via CrossOver 27 D3D12 game, borderless fullscreen window (2540x1650) Symptom When the game window becomes occluded — Mission Control, a system OSD (volume/brightness), or another window being brought to the front — the game never renders another frame. It does not crash: GPU utilization drops to 0%, the process stays alive with near-zero CPU, and it never recovers. Killing and restarting the game is the only way out. D3DMetal log at the moment it happens: [D3DMetal:FATAL:%llX][%s:%d] Failed to get drawable for HWND. Run with D3DM_NO_WINDOW=1 env. Question When CAMetalLayer/nextDrawable has no drawable (window not visible), is there a supported way for D3DMetal to skip frames instead of blocking forever? Is there an environment variable or configuration that makes D3DMetal treat "no drawable" as a recoverable condition? Does D3DM_NO_WINDOW=1 apply here, or is it only for headless/offscreen use? I understand apps should handle a nil drawable and continue, but this path is inside D3DMetal. Any guidance would help.
Replies
3
Boosts
0
Views
1.2k
Activity
6d
How to spin every cell of a 7×7 and 12×12 without one SCNView per cell
We render a grid of small USDZ models in SceneKit, one model per cell, and each model should spin continuously around its own local Y axis (one full turn every ~8 seconds). Simple grids of 7 and 12 cells work. A full 7×7 (49) or 12×12 (144) does not. Today each spinning cell is its own SCNView with rendersContinuously = true and an SCNAction.rotateBy on that cell’s pivot node. On macOS, opening a 7×7 of these views deadlocks SceneKit: layout stalls inside setFrameSize / setBackgroundColor while every render thread waits on the shared irradiance lock. We cap live views at 12 and keep the remaining cells as static bitmap snapshots, mounted in waves of four. Frame rate is already tiered (12 / 24 / 30 fps) and antialiasing is reduced on weaker devices. The same grid runs on macOS, iPad, and iPhone. What is the efficient way to spin every cell of a 7×7 and a 12×12 around its own axis? Specifically: one shared SCNScene (or one MTKView plus SCNRenderer) with many nodes, each rotating locally, instead of one SCNView per cell — and how should we share geometry, avoid per-view render loops, and stay off that irradiance lock during layout?
Replies
2
Boosts
0
Views
1.3k
Activity
1w
GameSaveSyncedDirectory.openDirectory() crashes in CloudDocs initUIApplicationWillResignActiveNotification
We use the GameSave framework to sync player save data to iCloud. Since iOS 27, our game crashes a few seconds after a cold launch, the first time it calls GameSaveSyncedDirectory.openDirectory(). We call the API only from the main actor, but the crash is on a cooperative thread inside GameSave: EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x400000000000bad0 libobjc.A.dylib objc_release CloudDocs initUIApplicationWillResignActiveNotification CloudDocs -[BRQuery _setQueryState:] CloudDocs -[BRQuery _runQuery] CloudDocs -[BRQuery executeWithOptions:] Foundation -[NSMetadataQuery startQuery] GameSave BundleUpdatesWaiter.initMetadataQuery() GameSave BundleUpdatesWaiter.init(bundleURL:) GameSave closure #1 in GameSyncedDirectoryHolder.allowReaders(for:)Other threads are inside the same BRQuery path at the same moment. The crash reproduces without GameSave: starting twoNSMetadataQuery objects at once on background threads in a fresh process crashes 94 times in 100 in the iOS 27.0 Simulator, and never on iOS 26.5, so this seems like a regression. Starting one query on a single thread never crashes. I've submitted a support request (FB25352978) so hopefully this will be looked at fairly soon - if anyone else runs into this it would be good to know!
Replies
3
Boosts
0
Views
640
Activity
1w
CGSetDisplayTransferByTable is broken on macOS Tahoe 26.4 RC (and 26.3.1) with MacBook M5 Pro, Max and Neo
The CGSetDisplayTransferByTable() is not working on the latest round of Mac hardware, namely the MacBook Neo (external display), MacBook M5 Pro (both built-in and external display) and possibly the M5 Max. All tested apps (BetterDisplay, MonitorControl, f.lux, Lunar) exhibit the very issue both in macOS Tahoe 26.3 and macOS Tahoe 26.4 RC. Tested on multiple Macs and installations on the MacBook Neo and MacBook M5 Pro. This issue breaks several display related macOS apps. Way to reproduce the issue using an affected app: Install the app BetterDisplay (https://betterdisplay.pro) Launch the app, open the app menu, choose Image Adjustments and try to adjust colors. Adjustments take no effect Way to reproduce the issue programmatically: Attempt to use the affected macOS API feature: https://developer.apple.com/documentation/coregraphics/cgsetdisplaytransferbytable(::::_:) Here are the FB numbers: FB22273730 (Filed this one as a developer on an unaffected MBP M3 Max) FB22273782 (Filed from an affected MBP M5 Pro running 26.4 RC, with debug info attached)
Replies
18
Boosts
7
Views
8.4k
Activity
1w