Довідник

Документацію написано англійською. Довідник — це docs/ з репозиторію hakios, скопійовані як є: точно, технічно, англійською.

Metal measurements

What the phone did, in numbers. How to get the same numbers: Metal on the Adreno. 120 frames a second has not been reached: not on hakios-metal, not on metal2vulkan, and not on OpenGL ES.

The setup

Phone POCO X5 Pro 5G (redwood), SM7325
GPU Adreno 642L at 550 MHz, the most this phone's GPU is rated for (adreno_speed=3, the default)
User space the Darwin 16.5 user space, laid out from your own IPSW
Panel 1080 x 2400 at 120 Hz
Rendered 1125 x 2436, scaled onto the panel by the driver
The run tools/metal-run.sh: eight cores, fb_hz=120 fb_threads=6 touch_poll_us=4000 wallpaper_freeze=1 metal_defer=1, the round of rc.jobs.bench four times

The results

Frames a second, 3 and 4 November 2026. hakios-metal as the last run of 4 November had it: wallpaper_freeze=1 metal_defer=1 fb_beam=1. metal2vulkan as measured on 3 November, before those.

Motion hakios-metal metal2vulkan
Page swipe 101 (100 to 104 over the runs) 50 to 57
Settings' scroll 89 to 91 (109 in one run of six, not repeated) 41
Opening an app about 90 not recorded
Home button 92 41 to 57
Frames over 16.7 ms 4% not recorded
GPU time a frame about 10 ms at the home screen, 3 November 14 to 21 ms

Both draw the system correctly. Not one of these is 120.

hakios-metal, inside a swipe. Once the finger has lifted, 185 of the animation's 205 frames take 8.3 ms, one refresh of the panel. While the finger drags, frames come at 75 to 80 a second, and the window server waits 8 to 14 ms on GPU fences. The 100 to 104 in the table covers both: tools/frames.py counts a gesture from the touch going down.

metal2vulkan. tu_debug=gmem and tu_debug=sysmem gave the same rates. Each frame renders to a tiled image and merges back into the IOSurface with a compute pass. The linear attachment path (VK_NV_linear_color_attachment) stays unused: the pass has a second attachment that is not linear, and the extension wants every colour attachment linear. With tu_debug=perf, no barrier turned GMEM off and no texture was shadowed.

Tried, and it did not help

What Arguments Result
Touch samples at 250 a second, not 125 touch_poll_us=4000, rwtouch every 4 ms swipes 100 to 102: unchanged
Surfaces let go of as soon as their pixels are on the panel, not when the next frame comes in MiniIOMobileFramebuffer unchanged
The iPhone XR's screen class, 1.85 times fewer pixels fbwidth=828 fbheight=1792 fbscale=2 fbsubtype=1792 idle GPU time 2.2 ms, not 6.8; gestures not faster; the wallpaper black
The iPhone 12 mini's screen class fbwidth=, fbheight=, fbscale=, fbsubtype= 103 to 107, with the red rdar://45025538 status bar
The wallpaper hidden, for swipes wallpaper_freeze=2 101 to 103, as with it: the wallpaper is not what holds swipes under 120. It is what held the home button: 78 hidden, against 28 with wallpaper_cache=1
The wallpaper's picture through -drawViewHierarchyInRect: wallpaper_freeze=1, first version one colour; with all of SpringBoard's windows hidden the screen itself was black. It now reads the IOSurface on the panel

What did help

On hakios-metal, each as the commit that made the change measured it, newest first.

Change Before After
wallpaper_freeze=1 metal_defer=1 home button 50 (28 with wallpaper_cache=1); Settings' scroll 90; frames over 16.7 ms 9% home button 89 to 92; scroll 91 (109 once); 4 to 6%; swipes 101 to 103
Eight cores, not one, for the first boot first frame at 159 s 86 s
fb_threads=6, not 3 Settings' scroll 75 84
wallpaper_cache=1 swipes 85 to 91; an app's close 40 swipes 97 to 103; an app's close 22 to 30, slower: the poster changes under its zoom
ui_lite=1 an app's close 40 55 to 58, with Reduce Transparency and Reduce Motion on
luma_boost left out, where QuartzCore's library has its own 83% of the GPU's timed passes gone; metal_luma_boost=1 draws it

metal2vulkan, on the way

When (3 November) What Result
vk_test Turnip alone a submission and its fence wait 0.5 ms at best, 2.0 on average
m2v_test the Metal device alone a full-screen clear committed and waited for in 1.08 ms
the window server, first the picture was wrong: grey shapes, the variants not chosen yet 3456 command buffers, 0 failed, 226k draws in 150 s; swipes 71 to 80, scroll 47, an app's open 25, GPU 17 to 36 ms a frame
the window server, right the variants chosen by label, own pages as textures swipes 50 to 57, scroll 41

The first window-server numbers are higher than the later ones because less was being drawn. They are here so that nobody takes them for a result.

OpenGL ES, for comparison

The default path, which is not Metal: Settings scrolled at 107 to 114 a second on the four big cores (cpus=4, fb_hz=120 ca_vbl=1, 31 October, hakios-sm7325 a8e7a87). The conditions differ from the table above in the core count and in the day's kernel, so that is a reference point and not a comparison run.

Tearing

The panel reads the very buffer the driver writes. It takes the scan 8.3 ms to read it and the driver about 3 ms to write it, so a frame written across the line being read came out torn: a piece of the last frame and a piece of this one, moving bands with doubled icons and text wherever something moved. Seen on the phone.

fb_beam=1, the default, writes each thread's rows behind the scan line, read from the interface's own INTF_LINE_COUNT, so that the next scan reads all of the new frame. The scan measured 2433 lines, 8338 us. It is looked at a minute after the driver starts; if the counter does not count as a line counter should, frames stay on their beat, and the log says so. 2 to 16 frames in 5 s miss their scan.

The bands were gone to the eye. That is the only evidence: xl screenshot cannot tell, because it sends live memory in pieces of 1 MiB, and the bands in its pictures are 243 rows apart.

It costs no frames. The same run otherwise, 4 November:

fb_beam=1 fb_beam=0
Page swipe 101 99
Settings' scroll 91 89
Home button 92 81
Frames over 16.7 ms 4% 6%

Вихідний код цієї сторінки