Lulucat

சாக் கருவியின் செயல்திறன்: முழுத்திரை pass-களிலிருந்து scissor rectangle-கள் வரை

Gaoge ZhangGaoge Zhang

Lulucat Notes-ன் சாக் கருவி அடர்த்தியான கையெழுத்துப் பகுதிகளில் மெதுவானது. Bottleneck 3,571 input samples அல்ல — ஒவ்வொரு frame-லும் செய்யப்பட்ட 70 முழுத்திரை scratch pass-கள்தான். நிராகரிக்கப்பட்ட குறைந்த-தெளிவு cache-ம், ஒவ்வொரு stroke-க்குமான scissor rectangle-மும் மீதிக் கதையைச் சொல்கின்றன.

255% zoom-ல் iPad-இல் இருக்கும் Lulucat Notes-ன் crop செய்யப்பட்ட காட்சி: சிவப்பு மற்றும் நீல சாக் கொண்டு ஒரு பாரம்பரிய சீனப் பகுதி எழுதப்பட்டுள்ளது; app toolbar-ன் ஒரு பகுதியும் தெரிகிறது.

இறுதி சாதனக் கட்டமைப்பில் சிவப்பு மற்றும் நீல சாக், 255% zoom-ல் 155 strokes.

Lulucat Notes-ன் சாக் கருவிக்கு ஒரு குறிப்பிட்ட செயல்திறன் சிக்கல் இருந்தது: வெற்றுப் பகுதியில் எழுதுவது சீராக இருந்தது; ஆனால் ஏற்கனவே சாக் strokes நிறைந்த பகுதியில் pen tip சென்றவுடன் அது பின்தங்கத் தொடங்கியது. அதே பகுதியில் தொடர்ந்து எழுதுவது canvas panning-ஐயும் படிப்படியாக மெதுவாக்கியது.

சாதாரணக் கைஎழுத்துள்ள ஒரு பக்கம் போதுமானதாக இருந்தது: 300% zoom, உள்ளூர் பகுதியில் 70 visible chalk strokes, மொத்தம் 3,571 input sample points. வெற்றுப் பகுதிகள் தொடர்ந்து சீராக இருந்தன; அந்த strokes குவிந்த பகுதி மட்டும் மெதுவானது.

சரிசெய்த பிறகு, அதே பக்கம் 255% zoom-ல் புதிய எழுத்தைத் தொடர்ந்து ஏற்கிறது; pen-down மற்றும் panning இரண்டிலும் ஏற்கனவே உள்ள strokes முழுத் தெளிவைத் தக்கவைத்துக்கொள்கின்றன.

255% zoom-ல் iPad-இல் இருக்கும் Lulucat Notes, சிவப்பு மற்றும் நீல சாக் கைஎழுத்தைக் காட்டுகிறது. உரை “天行健,君子以自强不息;地势坤,君子以厚德载物” — ஒரு பாரம்பரிய சீனப் பகுதி. மேல் வலது மூலையில் நீல Lulucat mascot உள்ளது. கீழ் toolbar stroke count 155, Save, Clear, மற்றும் 255% zoom slider-ஐக் காட்டுகிறது.

இறுதி சாதனத் திரைப்பிடிப்பு, மொத்தம் 155 strokes. இந்த zoom level-ல் pen-down அல்லது panning செய்யும்போது ஏற்கனவே உள்ள strokes-ன் தெளிவு தற்காலிகமாக மாறாது.

சாக் கருவிக்கு scratch texture ஏன் தேவை

ஒரு சாதாரண pen, ஒவ்வொரு வட்ட stamp-ஐயும் source-over blending மூலம் ink texture மீது நேரடியாக composite செய்ய முடியும். சாக் ஒரு grain-gating layer-ஐச் சேர்க்கிறது: renderer முதலில் ஒரு முழு stroke-க்கான body coverage மற்றும் depth-ஐச் சேகரிக்கிறது; பின்னர் எந்த இடங்களில் சாக் தூள் பட வேண்டும் என்பதைத் தீர்மானிக்க fixed grain texture-ஐப் பயன்படுத்துகிறது; இறுதியில் முடிவை ஏற்கனவே உள்ள ink மீது composite செய்கிறது.

இந்த scratch texture ஒரு சாக் stroke-ஐத் தனிமைப்படுத்துகிறது. இது முக்கியம், ஏனெனில் ஒரே stroke-க்குள் உள்ள stamps அதிகமாக overlap ஆகின்றன; ஒவ்வொரு stamp-மும் தனித்தனியாக grain-gate செய்யப்பட்டால், stroke-ன் மையக் கோடு மீண்டும் மீண்டும் வரும் நிறத்தைச் சேர்த்துக்கொண்டே இருக்கும், மேலும் சாக் துளைகள் sampling density-க்கு ஏற்ப மாறும்.

High zoom levels-ல், தற்போதைய viewport-ல் தெரியும் vector strokes-ஐ Lulucat Notes மீண்டும் வரைகிறது. பழைய செயலாக்கம் ஒவ்வொரு visible chalk stroke-க்கும் பின்வரும் படிகளைச் செய்தது:

  1. Main render encoder-ஐ முடித்தல்;
  2. Scratch texture-ஐ clear செய்தல்;
  3. இந்த chalk stroke-ஐ scratch-ல் வரைதல்;
  4. Main render encoder-ஐ மீண்டும் திறத்தல்;
  5. ஒரு full-screen triangle மூலம் scratch-ஐ drawable-க்கு மீண்டும் composite செய்தல்.

ஒரு stroke-ன் rendering semantics சரியாக இருந்தன; ஆனால் பணிப் பரப்பு மிகப் பெரியதாக இருந்தது. iPad-ன் drawable 2732×2048 — சுமார் 5.6 million pixels. ஒவ்வொரு chalk stroke-ம் ஒரு scratch pass மற்றும் ஒரு full-screen composite-ஐத் தூண்டியது. 70 chalk strokes என்றால் சுமார் 141 render encoders மற்றும் 70 full-screen composites.

Visible chalk strokes-ன் எண்ணிக்கை , drawable pixel count எனக் கொள்வோம். Pixel coverage-க்கு ஏற்ப அதிகரிக்கும் வேலையை மட்டும் எடுத்துக்கொண்டால், பழைய செயலாக்கம் சுமார்

என்பதற்கு நெருக்கமாக இருந்தது.

ஒவ்வொரு chalk stroke-க்கும் ஒரு நிலையான render-pass overhead இருந்தது; எனவே அந்தச் செலவும் உடன் நேர்கோட்டாக அதிகரித்தது. 3,571 input points இரண்டாம் நிலைச் செலவை மட்டுமே சேர்த்தன. உள்ளூர் stroke எண்ணிக்கையுடன் அதிகரித்தது, ஒவ்வொரு stroke-ம் தூண்டிய முழுத்திரைப் பணிப் பரப்பே.

அளவீடுகள் iPadOS 18.6.2 இயங்கும் 12.9-inch iPad Pro (5th generation, M1)-ல் எடுக்கப்பட்டன. மாற்றத்துக்கு முன்பும் பின்பும் அதே viewport-ன் GPU timestamps-ஐ ஒப்பிட்டோம்; இந்த குறிப்பிட்ட iPad-ல் உள்ள அதே Debug device build-ன் command-buffer timestamps-ஐப் பயன்படுத்தினோம் — இனி இதை LucasPad என்று அழைப்போம். கீழுள்ள வரம்புகள் பல frame-களின் logs-ல் காணப்பட்ட வழக்கமான ஏற்றத் தாழ்வுகள்; வெளியிடப்படும் பதிப்புக்கான frame-rate உறுதிமொழிகள் அல்ல. 70 visible chalk strokes இருக்கும்போது, ஒரு frame-க்கு வழக்கமாக 52–60 ms GPU time தேவைப்பட்டது; சுமார் 120 strokes உள்ள பகுதியில் GPU time 77–80 ms ஆக உயர்ந்தது.

Scratch மற்றும் composite pass-களின் முழுத்திரை rectangle area-வை வைத்து மதிப்பிட்டால், ஒவ்வொரு frame-க்குமான கோட்பாட்டு பணிப் பரப்பு சுமார் 783 million pixels-லிருந்து 1.34 billion pixels-ஆக உயர்ந்தது. இது rectangle area-களின் கூட்டுத்தொகை மட்டுமே; fragment invocation counts, video-memory read/write bytes அல்லது GPU hardware counters-க்கு இது சமமானதல்ல. Metal-ன் fast clear, attachment load/store மற்றும் pass switching ஆகியவை இன்னும் GPU மற்றும் driver கட்டுப்பாட்டிலேயே உள்ளன.

இதனால் வெற்றுப் பகுதிகள் ஏன் சீராக இருந்தன என்பதும் புரிகிறது. Visibility culling viewport-க்கு வெளியே உள்ள strokes-ஐத் தவிர்க்கிறது; வெற்றுப் பகுதியில் கிட்டத்தட்ட பூஜ்யம், அடர்த்தியான பகுதியில் தொடர்ந்து அதிகரிக்கிறது.

0.85 ms-ல் கிடைத்த தவறான பதில்

App-ல் ஏற்கனவே point ஒன்றுக்கு 2 pixels என்ற அளவில் bake செய்யப்பட்ட full-page ink texture இருந்தது. Writing, panning மற்றும் zooming நேரங்களில் இந்த texture-ஐ நேரடியாகக் காட்டிப் பார்த்தோம்; தற்போதைய Apple Pencil stroke-ஐ மட்டும் live vector-ஆக வைத்தோம். Interaction முடிந்ததும் high-resolution vector result-ஐ மீண்டும் render செய்ய ஒரு கூடுதல் frame பயன்படுத்தப்பட்டது.

இந்த அணுகுமுறை மிகச் சிறப்பாகச் செயல்பட்டது. அதே அடர்த்தியான பகுதியில் 300% zoom-ல் GPU time 0.84–0.85 ms-ஆகக் குறைந்தது; ஏற்கனவே உள்ள chalk strokes-ன் எண்ணிக்கையுடன் அது இனி அதிகரிக்கவில்லை.

ஆனால் உண்மையான சாதனத்தில் இருந்த சிக்கலும் அதே அளவு தெளிவாக இருந்தது. 300% zoom-ல் point ஒன்றுக்கு சுமார் ஆறு screen pixels தேவைப்பட்டன; cache வழங்கியது 2 மட்டுமே. Apple Pencil திரையைத் தொட்டவுடன், ஏற்கனவே உள்ள strokes அனைத்தும் மென்மையான low-resolution படமாக மாறின; Pencil-ஐ உயர்த்திய பிறகே அவை முழுத் தெளிவுக்குத் திரும்பின.

Tester சொன்னது: “நான் எழுதும்போது முழு canvas-மும் மங்கலாகிறது. கையை எடுத்தவுடன் அது மீண்டும் தெளிவாகிறது.”

இந்த optimization-ஐ நீக்கினோம். 0.85 ms என்பது அளந்ததில் கிடைத்த குறைந்தபட்ச முடிவு; ஆனால் அது ஏற்றுக்கொள்ளக்கூடிய சாக் கருவி அல்ல. ஏற்கனவே உள்ள strokes எழுதும் நேர feedback-ன் ஒரு பகுதி; pen-down செய்யும்போது அவற்றின் தெளிவு மாறக்கூடாது.

ஒவ்வொரு சாக் stroke-ஐயும் அதன் சொந்த rectangle-க்குள் வரையறுத்தல்

இறுதி சரிசெய்தல் per-stroke scratch மற்றும் per-stroke compositing-ஐத் தக்கவைத்துக்கொண்டு, அவற்றின் pixel பணிப் பரப்பை மட்டும் குறைத்தது. ஒவ்வொரு stroke-க்கும் அதன் அனைத்து stamp radii-ன் union-லிருந்து பெறப்பட்ட canvas bounding box ஏற்கனவே இருந்தது. Renderer அந்த bounding box-ஐ தற்போதைய viewport-ன் drawable coordinates-ஆக மாற்றி, antialiasing margin-க்காக 2 pixels-ஐச் சேர்க்கிறது:

அதே scissor rectangle மூன்று பணிகளுக்குப் பயன்படுத்தப்படுகிறது: scratch-ஐ clear செய்வது, இந்த stroke-ஐ வரைவது, மற்றும் முடிவை main surface-க்கு மீண்டும் composite செய்வது.

let rect = displayScissorRect(for: stroke.bounds, viewport: viewport)

scratchEncoder.setScissorRect(rect)
clearScratchExplicitly()
drawStrokeIntoScratch(stroke)

mainEncoder.setScissorRect(rect)
compositeChalkFromScratch(stroke)
mainEncoder.setScissorRect(fullDrawable)

இதே logic 4096² ink texture-ல் baking மற்றும் partial replay-க்கும் பயன்படுத்தப்படுகிறது. ஆகவே high-zoom display மற்றும் settled ink layer இரண்டு வேறு chalk behaviors-ஐ உருவாக்குவதில்லை.

இங்கே எளிதில் தவறவிடப்படும் இரண்டு details உள்ளன.

முதலில், ஒரு render pass-ன் loadAction = .clear, attachment load stage-ல் நடக்கிறது; rasterization scissor அதை வரையறுக்காது. அதைத் தொடர்ந்து பயன்படுத்தினால் scratch texture முழுவதும் இன்னும் clear ஆகும். சரிசெய்யப்பட்ட pass .dontCare-ஐப் பயன்படுத்தி, scissor-க்குள் clear_fragment-ஐ வரைகிறது. இந்த rectangle பின்னர் முழுமையாக எழுதப்படுகிறது; composite அதே rectangle-ஐ மட்டும் படிக்கிறது; எனவே பழைய attachment contents-ஐ load செய்ய வேண்டியதில்லை.

இரண்டாவதாக, ஒவ்வொரு chalk stroke-ன் composite முடிந்ததும் outer scissor-ஐ restore செய்ய வேண்டும். இந்த state restoration line-ஐ விட்டுவிட்டால், அடுத்தடுத்த pens, images அல்லது selections முந்தைய chalk stroke-ன் bounds-ஆல் தொடர்ந்து clip ஆகும்; strokes அல்லது images காணாமல் போனது போலத் தோன்றும்.

Chalk grain இன்னும் rectangle-க்குள் உள்ள local UV-களிலிருந்து அல்ல, absolute canvas coordinates-லிருந்து sample ஆகிறது. Scissor-ஐ நகர்த்துவது GPU செயல்படுத்தும் pixels-ஐ மட்டுமே மாற்றுகிறது; ஒவ்வொரு pixel படிக்கும் grain texture location மாறாது. ஆகவே அருகருகே உள்ள rectangles-க்கு இடையில் texture seams உருவாகாது; canvas-ஐ இழுப்பதால் grain drift ஆகாது.

Pixel workload-ஐ மட்டும் பார்த்தால், புதிய பணிப் பரப்பு சுமார்

என்பதற்கு நெருக்கமாக இருக்கும்; இதில் என்பது தற்போதைய திரையில் -வது chalk stroke-ன் axis-aligned bounding-box area. Render encoders-ன் எண்ணிக்கை குறையவில்லை; ஆனால் ஒவ்வொரு clear மற்றும் composite இப்போது அந்த stroke-ன் screen bounding box-க்குள் மட்டுப்படுத்தப்பட்டுள்ளது.

ஒரே நிற chalk strokes-ஐ ஏன் batch செய்யவில்லை

பக்கத்தில் உள்ள பெரும்பாலான chalk strokes ஒரே color மற்றும் density-ஐப் பகிர்கின்றன. ஆகவே பல பத்து strokes-ஐ scratch-ல் ஒரே நேரத்தில் வரைந்து, ஒரே முறை composite செய்யலாம் என்று தோன்றும். இது render passes-ன் எண்ணிக்கையை மேலும் குறைக்கும்; ஆனால் overlap ஆகும் பகுதிகளில் color மற்றும் grain semantics மாறிவிடும்.

ஒரு திட்டமிட்ட எளிமைப்படுத்தப்பட்ட நிலையைப் பார்ப்போம்: ஒரு குறிப்பிட்ட pixel-ல் இரண்டு strokes-க்கும் ஒரே grain-gate value உள்ளது; body coverages மற்றும் . உண்மையான shader-ல் gate ஒவ்வொரு stroke-ன் pressure depth-ஐயும் சார்ந்தது; batching பொதுவாக அதே விளைவைத் தராது என்பதை காட்ட இந்த எளிய நிலை போதுமானது. தற்போதைய per-stroke compositing தருவது

ஆனால் bodies-ஐ முதலில் merge செய்து, ஒரே gate-ஐப் பயன்படுத்தினால் கிடைப்பது

இரண்டிற்கும் இடையிலான வேறுபாடு . இரண்டு strokes overlap ஆகும்போதும், grain gate pure zero அல்லது pure one அல்லாதபோதும், முடிவுகள் வேறுபடும். நேரடியாக batch செய்வது intersections-ல் சாக் தூள் படியும் முறையை மாற்றிவிடும்.

துல்லியமான batching-க்கு stroke pixels ஒன்றுக்கொன்று overlap ஆகவில்லை என்பதை நிரூபிக்க வேண்டும்; அல்லது ஒவ்வொரு stroke-க்கும் தனித்தனி atlas region-ஐ ஒதுக்கி, original order-ல் composite செய்ய வேண்டும். இறுதி சாதனச் சோதனையில் scissor அணுகுமுறையே வைத்துக்கொள்ளப்பட்டது; எனவே இந்தச் சுற்றில் atlas அல்லது அதன் management complexity சேர்க்கப்படவில்லை.

ஒரு பில்லியன் pixels-லிருந்து சில மில்லியன்களுக்குத் திரும்புதல்

இறுதி சாதனச் சோதனை அளவீடுகள்:

நிலைசரிசெய்வதற்கு முன்துல்லியமான scissor
70 visible chalk strokes, 300% zoom, writingGPU 52–60 ms≈ 9–10 ms
≈ 121 visible chalk strokes, 300% zoomGPU 77–80 ms13.7–15.6 ms
ஒவ்வொரு frame-க்கும் theoretical rectangle scope (scratch + composite)783 M–1.34 B pixels≈ 1.7 M–3 M pixels

ஒரு சாதன ஆவணத்தில் இருந்த 3,452 strokes மற்றும் 202,710 sample points-ஐப் பயன்படுத்தி clipping bounds-ஐயும் சரிபார்த்தோம். 0.5×, 1×, 2×, 3×, 5× மற்றும் 8× zoom-ல் 186,408 viewport cases உருவாக்கப்பட்டன; non-zero coverage உருவாக்கக்கூடிய ஒவ்வொரு point sprite-மும் கணக்கிடப்பட்ட scissor-க்குள் இருந்தது. இந்தச் சோதனை canvas edges, viewport edges மற்றும் பல்வேறு offset combinations-ஐ உள்ளடக்கியது.

சோதனையில் உள்ள குறியீடு interaction state அடிப்படையில் low-resolution LOD-க்கு மாறாது. Low zoom levels-ல் full-page ink texture-ஐயே காட்டுகிறது; high zoom levels-ல் visible strokes-ஐ vector-களாக redraw செய்கிறது. Threshold-ன் ஒரே பக்கத்தில் இருக்கும் வரை, pen-down மற்றும் panning ஏற்கனவே உள்ள strokes-ஐ வேறு clarity level-ஆக மாற்றாது. High-zoom vector redraw-ன் போது ஒவ்வொரு chalk stroke-ன் scratch clear மற்றும் composite அதன் சொந்த screen bounding box-ஐ மட்டுமே மூடுகின்றன.

GPU time தெளிவை பதிவு செய்யவில்லை

GPU செயல்திறன் சிக்கல்கள் data structure-ல் மிகவும் வெளிப்படையாகத் தெரியும் எண்ணிக்கையுடன் அவசியம் scale ஆகாது. இங்கே 3,571 input points எளிதான சந்தேகமாக இருந்தன; ஆனால் frame time-ஐ நிர்ணயித்தது 70 chalk strokes ஒவ்வொன்றும் தூண்டிய full-screen work மற்றும் அதனுடன் வந்த render-pass switching.

காட்சித் semantics பயன்படுத்தக்கூடிய optimizations-ஐயும் கட்டுப்படுத்தின. Per-stroke scratch, original compositing order மற்றும் absolute canvas grain coordinates ஆகியவற்றை விருப்பம்போல் அகற்ற முடியாது. Same color மற்றும் same density என்பது parameters ஒன்றே என்பதைக் காட்டும்; overlap ஆகும் முடிவுகளை merge செய்யலாம் என்பதை அது நிரூபிக்காது.

உண்மையான சாதன feedback GPU time குறைவாக இருந்த version-ஐ நிராகரித்தது. “நான் எழுதும்போது முழு canvas-மும் மங்கலாகிறது” என்ற கருத்து, அளவீடு மட்டும் வெளிப்படுத்தாத product constraint-ஐச் சொன்னது: Apple Pencil திரையைத் தொடும்போது, பயனர் ஏற்கனவே உள்ள strokes-ஐயும் கவனிக்கிறார்.

சோதனையில் ஏற்றுக்கொள்ளப்பட்ட செயலாக்கம் புதிய interaction cache layer-ஐச் சேர்க்கவில்லை; clarity-ஐயும் குறைக்கவில்லை. High-zoom vector redraw ஒவ்வொரு chalk stroke-ன் வேலையை அதன் சொந்த screen bounding box-க்குள் மட்டுமே கட்டுப்படுத்துகிறது. சோதனை build-ஐ மீண்டும் LucasPad-ல் ஏற்றியபோது feedback: “மிகவும் நன்றாக இருக்கிறது.”