Lulucat

ಚಾಕ್ ಉಪಕರಣದ ಕಾರ್ಯಕ್ಷಮತೆ: ಪೂರ್ಣ-ಪರದೆ ಪಾಸ್‌ಗಳಿಂದ scissor ಆಯತಗಳವರೆಗೆ

Gaoge ZhangGaoge Zhang

ದಟ್ಟ ಕೈಬರಹದ ಪ್ರದೇಶಗಳಲ್ಲಿ Lulucat Notes‌ನ ಚಾಕ್ ಉಪಕರಣ ನಿಧಾನವಾಗುತ್ತಿತ್ತು. ಮುಖ್ಯ ಅಡಚಣೆ 3,571 ಇನ್‌ಪುಟ್ ಸ್ಯಾಂಪಲ್‌ಗಳಲ್ಲ — ಪ್ರತಿ ಫ್ರೇಮ್‌ನಲ್ಲಿ ನಡೆಯುತ್ತಿದ್ದ 70 ಪೂರ್ಣ-ಪರದೆ scratch ಪಾಸ್‌ಗಳಲ್ಲಿತ್ತು. ತಿರಸ್ಕರಿಸಿದ ಕಡಿಮೆ-ರೆಸಲ್ಯೂಶನ್ ಕ್ಯಾಶ್ ಮತ್ತು ಪ್ರತಿ ಸ್ಟ್ರೋಕ್‌ಗೆ ಸೇರಿದ scissor ಆಯತವು ಉಳಿದ ಕಥೆಯನ್ನು ಹೇಳುತ್ತವೆ.

255% ಜೂಮ್‌ನಲ್ಲಿ iPad ಮೇಲಿನ Lulucat Notes‌ನ ಕತ್ತರಿಸಿದ ದೃಶ್ಯ; ಕೆಂಪು ಮತ್ತು ನೀಲಿ ಚಾಕ್‌ನಲ್ಲಿ ಬರೆದ ಚೀನೀ ಶಾಸ್ತ್ರೀಯ ಭಾಗ ಹಾಗೂ ಆಪ್‌ನ ಟೂಲ್‌ಬಾರ್‌ನ ಒಂದು ಭಾಗ ಕಾಣುತ್ತದೆ.

ಅಂತಿಮ ಪರಿಶೀಲನೆಗೆ ಬಳಸಿದ device build‌ನ ಕೆಂಪು ಮತ್ತು ನೀಲಿ ಚಾಕ್, 255% ಜೂಮ್‌ನಲ್ಲಿ 155 ಸ್ಟ್ರೋಕ್‌ಗಳು.

Lulucat Notes‌ನ ಚಾಕ್ ಉಪಕರಣಕ್ಕೆ ಒಂದು ನಿರ್ದಿಷ್ಟ ಕಾರ್ಯಕ್ಷಮತಾ ಸಮಸ್ಯೆ ಇತ್ತು: ಖಾಲಿ ಪ್ರದೇಶದಲ್ಲಿ ಬರೆಯುವುದು ಸರಾಗವಾಗಿತ್ತು, ಆದರೆ ಈಗಾಗಲೇ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳಿಂದ ತುಂಬಿದ ಪ್ರದೇಶಕ್ಕೆ ಹೋದಾಗ ಪೆನ್‌ನ ತುದಿ ಹಿಂದೆ ಬೀಳಲು ಆರಂಭಿಸುತ್ತಿತ್ತು. ಅದೇ ಪ್ರದೇಶದಲ್ಲಿ ಬರೆಯುವುದನ್ನು ಮುಂದುವರಿಸಿದಂತೆ ಕ್ಯಾನ್ವಾಸ್ ಪ್ಯಾನಿಂಗ್ ಕೂಡ ನಿಧಾನವಾಗುತ್ತಿತ್ತು.

ಸಾಮಾನ್ಯ ಕೈಬರಹದ ಒಂದೇ ಪುಟ ಸಮಸ್ಯೆ ಉಂಟುಮಾಡಲು ಸಾಕಾಗುತ್ತಿತ್ತು: 300% ಜೂಮ್, ಸ್ಥಳೀಯ ಪ್ರದೇಶದಲ್ಲಿ ಕಾಣುವ 70 ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳು, ಒಟ್ಟು 3,571 ಇನ್‌ಪುಟ್ ಸ್ಯಾಂಪಲ್ ಬಿಂದುಗಳು. ಖಾಲಿ ಪ್ರದೇಶಗಳು ಸರಾಗವಾಗಿಯೇ ಉಳಿದವು; ಸ್ಟ್ರೋಕ್‌ಗಳು ದಟ್ಟವಾಗಿದ್ದ ಪ್ರದೇಶ ಮಾತ್ರ ನಿಧಾನವಾಯಿತು.

ತಿದ್ದುಪಡಿಯ ನಂತರ ಅದೇ ಪುಟದಲ್ಲಿ 255% ಜೂಮ್‌ನಲ್ಲಿ ಹೊಸ ಬರಹವನ್ನು ಮುಂದುವರಿಸಬಹುದು, ಮತ್ತು ಪೆನ್ ಕೆಳಗಿಟ್ಟಿರುವಾಗಲೂ ಪ್ಯಾನ್ ಮಾಡುವಾಗಲೂ ಈಗಿರುವ ಸ್ಟ್ರೋಕ್‌ಗಳು ಸಂಪೂರ್ಣ ಸ್ಪಷ್ಟತೆಯನ್ನು ಉಳಿಸಿಕೊಳ್ಳುತ್ತವೆ.

255% ಜೂಮ್‌ನ iPad ಮೇಲಿನ Lulucat Notes ಕೆಂಪು ಮತ್ತು ನೀಲಿ ಚಾಕ್ ಕೈಬರಹವನ್ನು ತೋರಿಸುತ್ತದೆ. ಪಠ್ಯ "天行健,君子以自强不息;地势坤,君子以厚德载物" ಎಂದು ಓದಿಸುತ್ತದೆ — ಇದು ಚೀನೀ ಶಾಸ್ತ್ರೀಯ ಭಾಗ. ಮೇಲಿನ ಬಲಭಾಗದಲ್ಲಿ ನೀಲಿ Lulucat ಮ್ಯಾಸ್ಕಾಟ್ ಇದೆ. ಕೆಳಗಿನ ಟೂಲ್‌ಬಾರ್‌ನಲ್ಲಿ 155 ಸ್ಟ್ರೋಕ್‌ಗಳ ಎಣಿಕೆ, Save, Clear ಮತ್ತು 255% ಜೂಮ್ ಸ್ಲೈಡರ್ ಕಾಣುತ್ತವೆ.

ಅಂತಿಮ ಪರಿಶೀಲನೆಗೆ ಬಳಸಿದ device‌ನ ಸ್ಕ್ರೀನ್‌ಶಾಟ್, ಒಟ್ಟು 155 ಸ್ಟ್ರೋಕ್‌ಗಳು. ಈ ಜೂಮ್ ಮಟ್ಟದಲ್ಲಿ ಪೆನ್ ಕೆಳಗಿಡುವುದರಿಂದಲೂ ಪ್ಯಾನ್ ಮಾಡುವುದರಿಂದಲೂ ಈಗಿರುವ ಸ್ಟ್ರೋಕ್‌ಗಳ ಸ್ಪಷ್ಟತೆ ತಾತ್ಕಾಲಿಕವಾಗಿ ಬದಲಾಗುವುದಿಲ್ಲ.

ಚಾಕ್‌ಗೆ scratch ಟೆಕ್ಸ್ಚರ್ ಏಕೆ ಬೇಕು

ಸಾಮಾನ್ಯ ಪೆನ್ ಪ್ರತಿಯೊಂದು ವೃತ್ತಾಕಾರದ stamp ಅನ್ನು source-over blending ಬಳಸಿ ink ಟೆಕ್ಸ್ಚರ್ ಮೇಲೆ ನೇರವಾಗಿ composite ಮಾಡಬಹುದು. ಚಾಕ್ ಒಂದು grain-gating ಪದರವನ್ನು ಸೇರಿಸುತ್ತದೆ: ರೆಂಡರರ್ ಮೊದಲು ಸಂಪೂರ್ಣ ಸ್ಟ್ರೋಕ್‌ನ body coverage ಮತ್ತು depth ಅನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ, ನಂತರ ಯಾವ ಸ್ಥಾನಗಳಿಗೆ ಚಾಕ್ ಪುಡಿ ಬೀಳಬೇಕು ಎಂದು ನಿಗದಿತ grain ಟೆಕ್ಸ್ಚರ್ ಬಳಸಿ ನಿರ್ಧರಿಸುತ್ತದೆ, ಕೊನೆಯಲ್ಲಿ ಫಲಿತಾಂಶವನ್ನು ಈಗಿರುವ ink ಮೇಲೆ composite ಮಾಡುತ್ತದೆ.

ಈ scratch ಟೆಕ್ಸ್ಚರ್ ಒಂದೇ ಚಾಕ್ ಸ್ಟ್ರೋಕ್ ಅನ್ನು ಪ್ರತ್ಯೇಕಿಸುತ್ತದೆ. ಒಂದೇ ಸ್ಟ್ರೋಕ್‌ನೊಳಗಿನ stamps ಬಹಳವಾಗಿ ಒಂದರ ಮೇಲೊಂದು ಬೀಳುವುದರಿಂದ ಈ ಪ್ರತ್ಯೇಕತೆ ಮುಖ್ಯ; ಪ್ರತಿಯೊಂದು stamp‌ಗೆ ಪ್ರತ್ಯೇಕವಾಗಿ grain gate ಅನ್ವಯಿಸಿದರೆ ಸ್ಟ್ರೋಕ್‌ನ ಮಧ್ಯರೇಖೆಯಲ್ಲಿ ಬಣ್ಣ ಮರುಮರು ಸೇರುತ್ತದೆ ಮತ್ತು ಸ್ಯಾಂಪ್ಲಿಂಗ್ ಸಾಂದ್ರತೆಯೊಂದಿಗೆ ಚಾಕ್‌ನ ರಂಧ್ರಗಳು ಸ್ಥಳ ಬದಲಿಸುತ್ತವೆ.

ಹೆಚ್ಚಿನ ಜೂಮ್ ಮಟ್ಟಗಳಲ್ಲಿ Lulucat Notes ಪ್ರಸ್ತುತ viewport‌ನಲ್ಲಿ ಕಾಣುವ vector ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು ಮರು-ರೆಂಡರ್ ಮಾಡುತ್ತದೆ. ಹಳೆಯ implementation ಕಾಣುವ ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗೆ ಈ ಹಂತಗಳನ್ನು ನಡೆಸುತ್ತಿತ್ತು:

  1. main render encoder ಅನ್ನು ಕೊನೆಗೊಳಿಸುವುದು;
  2. scratch ಟೆಕ್ಸ್ಚರ್ ಅನ್ನು ತೆರವುಗೊಳಿಸುವುದು;
  3. ಈ ಒಂದೇ ಚಾಕ್ ಸ್ಟ್ರೋಕ್ ಅನ್ನು scratch ಒಳಗೆ draw ಮಾಡುವುದು;
  4. main render encoder ಅನ್ನು ಮತ್ತೆ ತೆರೆಯುವುದು;
  5. ಪೂರ್ಣ-ಪರದೆ ತ್ರಿಭುಜ ಬಳಸಿ scratch ಅನ್ನು drawable‌ಗೆ ಹಿಂದಿರುಗಿ composite ಮಾಡುವುದು.

ಒಂದು ಸ್ಟ್ರೋಕ್‌ನ ಅರ್ಥ ಸರಿಯಾಗಿತ್ತು, ಆದರೆ ಕೆಲಸದ ವ್ಯಾಪ್ತಿ ಬಹಳ ದೊಡ್ಡದಾಗಿತ್ತು. iPad‌ನ drawable 2732×2048 — ಸುಮಾರು 5.6 ಮಿಲಿಯನ್ ಪಿಕ್ಸೆಲ್‌ಗಳು. ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್ ಒಂದು scratch pass ಮತ್ತು ಒಂದು ಪೂರ್ಣ-ಪರದೆ composite ಅನ್ನು ಪ್ರಚೋದಿಸುತ್ತಿತ್ತು. 70 ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳು ಎಂದರೆ ಸುಮಾರು 141 render encoder‌ಗಳು ಮತ್ತು 70 ಪೂರ್ಣ-ಪರದೆ composite‌ಗಳು.

ಕಾಣುವ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮತ್ತು drawable ಪಿಕ್ಸೆಲ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಎಂದುಕೊಳ್ಳಿ. ಪಿಕ್ಸೆಲ್ ವ್ಯಾಪ್ತಿಯೊಂದಿಗೆ ಹೆಚ್ಚಾಗುವ ಕೆಲಸವನ್ನು ಮಾತ್ರ ಪರಿಗಣಿಸಿದರೆ, ಹಳೆಯ ಅನುಷ್ಠಾನ ಹೀಗಿರುತ್ತದೆ:

ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗೆ ಸ್ಥಿರವಾದ render-pass overhead ಕೂಡ ಇತ್ತು; ಆದ್ದರಿಂದ ಆ ವೆಚ್ಚವೂ ಜೊತೆಗೆ ರೇಖೀಯವಾಗಿ ಹೆಚ್ಚುತ್ತಿತ್ತು. 3,571 ಇನ್‌ಪುಟ್ ಪಾಯಿಂಟ್‌ಗಳು ದ್ವಿತೀಯ ವೆಚ್ಚವನ್ನು ಮಾತ್ರ ಸೇರಿಸಿದವು. ಸ್ಥಳೀಯ ಸ್ಟ್ರೋಕ್‌ಗಳ ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಹೆಚ್ಚಾದದ್ದು, ಪ್ರತಿಯೊಂದು ಸ್ಟ್ರೋಕ್ ಪ್ರಚೋದಿಸಿದ ಪೂರ್ಣ-ಪರದೆ ಕೆಲಸದ ವ್ಯಾಪ್ತಿ.

iPadOS 18.6.2 ಚಾಲನೆಯಲ್ಲಿದ್ದ 12.9-inch iPad Pro (5th generation, M1) ಮೇಲೆ ಅಳತೆಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಯಿತು. ಈ ನಿರ್ದಿಷ್ಟ iPad‌ನ ಅದೇ Debug device build‌ನಲ್ಲಿ command-buffer timestamps ಬಳಸಿ, ಬದಲಾವಣೆಯ ಮೊದಲು ಮತ್ತು ನಂತರದ ಅದೇ viewport‌ನ GPU timestamps ಅನ್ನು ಹೋಲಿಸಲಾಯಿತು. ಕೆಳಗಿನ ವ್ಯಾಪ್ತಿಗಳು ಅನೇಕ ಫ್ರೇಮ್‌ಗಳ log‌ಗಳಲ್ಲಿ ಕಂಡ ಸಾಮಾನ್ಯ ಏರಿಳಿತಗಳು; ಇವು ವಿತರಿಸಲಿರುವ ಆವೃತ್ತಿಯ frame-rate ಭರವಸೆಗಳಲ್ಲ. 70 ಕಾಣುವ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳಿದ್ದಾಗ ಒಂದು ಫ್ರೇಮ್‌ಗೆ ಸಾಮಾನ್ಯವಾಗಿ 52–60 ms GPU ಸಮಯ ಬೇಕಾಗುತ್ತಿತ್ತು; ಸುಮಾರು 120 ಸ್ಟ್ರೋಕ್‌ಗಳ ಪ್ರದೇಶದಲ್ಲಿ GPU ಸಮಯ 77–80 msಗೆ ಏರಿತು.

scratch ಮತ್ತು composite ಪಾಸ್‌ಗಳ ಪೂರ್ಣ-ಪರದೆ ಆಯತದ ವಿಸ್ತೀರ್ಣದ ಆಧಾರದ ಮೇಲೆ ಅಂದಾಜಿಸಿದಾಗ, ಪ್ರತಿ ಫ್ರೇಮ್‌ನ ಸೈದ್ಧಾಂತಿಕ ಕೆಲಸದ ವ್ಯಾಪ್ತಿ ಸುಮಾರು 783 ಮಿಲಿಯನ್ ಪಿಕ್ಸೆಲ್‌ಗಳಿಂದ 1.34 ಬಿಲಿಯನ್ ಪಿಕ್ಸೆಲ್‌ಗಳಿಗೆ ಬೆಳೆದಿತ್ತು. ಈ ಅಂಕೆ ಆಯತಗಳ ವಿಸ್ತೀರ್ಣಗಳ ಮೊತ್ತ; ಇದು fragment invocation counts, video-memory read/write bytes ಅಥವಾ GPU hardware counters‌ಗೆ ಸಮಾನವಲ್ಲ. Metal‌ನ fast clear, attachment load/store ಮತ್ತು pass switching ಇನ್ನೂ GPU ಮತ್ತು driver ನಿಯಂತ್ರಣದಲ್ಲಿವೆ.

ಖಾಲಿ ಪ್ರದೇಶಗಳು ಸರಾಗವಾಗಿಯೇ ಉಳಿದದ್ದನ್ನೂ ಇದು ವಿವರಿಸುತ್ತದೆ. visibility culling viewport‌ನ ಹೊರಗಿನ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು ಬಿಟ್ಟುಬಿಡುತ್ತದೆ; ಖಾಲಿ ಪ್ರದೇಶದಲ್ಲಿ ಶೂನ್ಯಕ್ಕೆ ಸಮೀಪ, ದಟ್ಟ ಪ್ರದೇಶದಲ್ಲಿ ನಿರಂತರವಾಗಿ ಏರುತ್ತದೆ.

0.85 msನಲ್ಲಿ ಬಂದ ತಪ್ಪು ಉತ್ತರ

ಆಪ್‌ನಲ್ಲಿ ಈಗಾಗಲೇ ಪ್ರತಿ pointಗೆ ಎರಡು ಪಿಕ್ಸೆಲ್‌ಗಳಲ್ಲಿ baked ಮಾಡಿದ ಸಂಪೂರ್ಣ ಪುಟದ ink texture ಇತ್ತು. ಬರೆಯುವಾಗ, ಪ್ಯಾನ್ ಮಾಡುವಾಗ ಮತ್ತು ಜೂಮ್ ಮಾಡುವಾಗ ಈ ಟೆಕ್ಸ್ಚರ್ ಅನ್ನು ನೇರವಾಗಿ ತೋರಿಸಿ, ಪ್ರಸ್ತುತ Apple Pencil ಸ್ಟ್ರೋಕ್ ಒಂದನ್ನಷ್ಟೇ live vector ಆಗಿ ಉಳಿಸುವ ವಿಧಾನವನ್ನು ನಾವು ಪ್ರಯತ್ನಿಸಿದೆವು; interaction ಮುಗಿದ ನಂತರ ಇನ್ನೊಂದು ಫ್ರೇಮ್ ಹೆಚ್ಚಿನ-ರೆಸಲ್ಯೂಶನ್ vector ಫಲಿತಾಂಶವನ್ನು ಮರು-ರೆಂಡರ್ ಮಾಡುತ್ತಿತ್ತು.

ಈ ವಿಧಾನ ಬಹಳ ಚೆನ್ನಾಗಿ ಕೆಲಸ ಮಾಡಿತು. ಅದೇ ದಟ್ಟ ಪ್ರದೇಶದಲ್ಲಿ 300% ಜೂಮ್‌ನಲ್ಲಿ GPU ಸಮಯ 0.84–0.85 msಗೆ ಇಳಿಯಿತು ಮತ್ತು ಈಗಾಗಲೇ ಇರುವ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳ ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಇನ್ನು ಹೆಚ್ಚಲಿಲ್ಲ.

ನೈಜ device‌ನ ಸಮಸ್ಯೆಯೂ ಅಷ್ಟೇ ಸ್ಪಷ್ಟವಾಗಿತ್ತು. 300% ಜೂಮ್‌ನಲ್ಲಿ ಪ್ರತಿ pointಗೆ ಸುಮಾರು ಆರು screen pixels ಬೇಕಾಗುತ್ತಿತ್ತು, ಆದರೆ cache ಕೇವಲ ಎರಡು ನೀಡುತ್ತಿತ್ತು. Apple Pencil ಪರದೆಯನ್ನು ತಾಕಿದ ಕ್ಷಣಕ್ಕೆ ಈಗಿರುವ ಎಲ್ಲಾ ಸ್ಟ್ರೋಕ್‌ಗಳು ಮೃದುವಾದ, ಕಡಿಮೆ-ರೆಸಲ್ಯೂಶನ್ ಚಿತ್ರವಾಗಿ ಬದಲಾದವು; Pencil ಎತ್ತಿದಾಗ ಅವು ಮತ್ತೆ ಸಂಪೂರ್ಣ ಸ್ಪಷ್ಟವಾದವು.

ಪರೀಕ್ಷಕ ಹೀಗೆ ಹೇಳಿದರು: “ನಾನು ಬರೆಯುವಾಗ ಇಡೀ ಕ್ಯಾನ್ವಾಸ್ ಮಸುಕಾಗುತ್ತದೆ. ಕೈ ಬಿಡುತ್ತಿದ್ದಂತೆ ಮತ್ತೆ ಸ್ಪಷ್ಟವಾಗುತ್ತದೆ.”

ಈ optimization ತೆಗೆದುಹಾಕಲಾಯಿತು. 0.85 ms ಅಳೆಯಲಾದ ಅತಿ ಕಡಿಮೆ ಫಲಿತಾಂಶವಾಗಿತ್ತು, ಆದರೆ ಅದು ಸ್ವೀಕಾರಾರ್ಹ ಚಾಕ್ ಉಪಕರಣವಾಗಿರಲಿಲ್ಲ. ಈಗಿರುವ ಸ್ಟ್ರೋಕ್‌ಗಳು ಬರೆಯುವಾಗ ದೊರೆಯುವ ಪ್ರತಿಕ್ರಿಯೆಯ ಭಾಗ; ಪೆನ್ ಕೆಳಗಿಟ್ಟ ಕ್ಷಣದಲ್ಲೇ ಅವುಗಳ ಸ್ಪಷ್ಟತೆ ಬದಲಾಗಬಾರದು.

ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್ ಅನ್ನು ಅದರದೇ ಆಯತಕ್ಕೆ ಸೀಮಿತಗೊಳಿಸುವುದು

ಅಂತಿಮ ತಿದ್ದುಪಡಿ ಪ್ರತಿ-ಸ್ಟ್ರೋಕ್ scratch ಮತ್ತು ಪ್ರತಿ-ಸ್ಟ್ರೋಕ್ compositing ಅನ್ನು ಉಳಿಸಿಕೊಂಡು, ಪಿಕ್ಸೆಲ್ ಕೆಲಸದ ವ್ಯಾಪ್ತಿಯನ್ನು ಮಾತ್ರ ಕಡಿಮೆ ಮಾಡಿತು. ಪ್ರತಿಯೊಂದು ಸ್ಟ್ರೋಕ್‌ಗೆ ಅದರ ಎಲ್ಲ stamp radii‌ಗಳ union‌ನಿಂದ ಪಡೆದ canvas bounding box ಈಗಾಗಲೇ ಇತ್ತು. ರೆಂಡರರ್ ಈ bounding box ಅನ್ನು ಪ್ರಸ್ತುತ viewport‌ನ drawable coordinates‌ಗೆ ಪರಿವರ್ತಿಸಿ, antialiasing margin‌ಗಾಗಿ ಎರಡು ಪಿಕ್ಸೆಲ್‌ಗಳನ್ನು ಹೆಚ್ಚಿಸುತ್ತದೆ:

ಅದೇ scissor rectangle ಅನ್ನು ಮೂರು ಕೆಲಸಗಳಿಗೆ ಬಳಸಲಾಗುತ್ತದೆ: scratch ತೆರವುಗೊಳಿಸಲು, ಸ್ಟ್ರೋಕ್ draw ಮಾಡಲು ಮತ್ತು ಫಲಿತಾಂಶವನ್ನು ಮುಖ್ಯ ಮೇಲ್ಮೈಗೆ ಹಿಂದಿರುಗಿ composite ಮಾಡಲು.

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

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

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

4096² ink texture‌ನ baking ಮತ್ತು partial replayಗೂ ಇದೇ logic ಬಳಕೆಯಾಗುತ್ತದೆ. ಆದ್ದರಿಂದ ಹೆಚ್ಚಿನ-ಜೂಮ್ display ಮತ್ತು ನೆಲೆಯಾಗಿರುವ ink layer ಎರಡು ವಿಭಿನ್ನ ಚಾಕ್ ವರ್ತನೆಗಳನ್ನು ಸೃಷ್ಟಿಸುವುದಿಲ್ಲ.

ಇಲ್ಲಿ ಎರಡು ವಿವರಗಳು ಸುಲಭವಾಗಿ ಗಮನ ತಪ್ಪುತ್ತವೆ.

ಮೊದಲನೆಯದು, render pass‌ನ loadAction = .clear attachment load ಹಂತದಲ್ಲಿ ನಡೆಯುತ್ತದೆ ಮತ್ತು rasterization scissor‌ನಿಂದ ಸೀಮಿತವಾಗುವುದಿಲ್ಲ. ಅದನ್ನು ಮುಂದುವರಿಸಿ ಬಳಸಿದರೆ scratch texture ಸಂಪೂರ್ಣವಾಗಿ ತೆರವುಗೊಳ್ಳುತ್ತದೆ. ಸರಿಪಡಿಸಿದ pass .dontCare ಬಳಸುತ್ತದೆ; ನಂತರ scissor ಒಳಗೆ clear_fragment ಅನ್ನು draw ಮಾಡುತ್ತದೆ. ಈ rectangle ಅನ್ನು ನಂತರ ಸಂಪೂರ್ಣವಾಗಿ ಬರೆಯಲಾಗುತ್ತದೆ ಮತ್ತು composite ಅದೇ rectangle ಅನ್ನು ಮಾತ್ರ ಓದುತ್ತದೆ; ಆದ್ದರಿಂದ ಹಳೆಯ attachment contents ಅನ್ನು load ಮಾಡಬೇಕಾಗಿಲ್ಲ.

ಎರಡನೆಯದು, ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ನ composite ಮುಗಿದ ನಂತರ ಹೊರಗಿನ scissor ಅನ್ನು restore ಮಾಡಬೇಕು. ಈ state restoration ಸಾಲನ್ನು ಬಿಟ್ಟರೆ ನಂತರದ pens, images ಅಥವಾ selections ಹಿಂದಿನ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ನ bounds‌ನಿಂದ clip ಆಗುತ್ತವೆ; ಅವು ಕಾಣೆಯಾದ ಸ್ಟ್ರೋಕ್‌ಗಳು ಅಥವಾ ಚಿತ್ರಗಳಂತೆ ಕಾಣುತ್ತವೆ.

ಚಾಕ್‌ನ grain ಇನ್ನೂ rectangle ಒಳಗಿನ local UVಗಳಿಂದಲ್ಲ, absolute canvas coordinates‌ನಿಂದ sample ಮಾಡುತ್ತದೆ. Scissor ಬದಲಿಸಿದಾಗ GPU process ಮಾಡುವ pixels ಮಾತ್ರ ಬದಲಾಗುತ್ತವೆ; ಪ್ರತಿಯೊಂದು pixel ಓದುವ grain texture location ಬದಲಾಗುವುದಿಲ್ಲ. ಆದ್ದರಿಂದ ಪಕ್ಕಪಕ್ಕದ rectangles ನಡುವೆ texture seams ಉಂಟಾಗುವುದಿಲ್ಲ, ಮತ್ತು canvas ಅನ್ನು drag ಮಾಡಿದಾಗ grain drift ಆಗುವುದಿಲ್ಲ.

ಪಿಕ್ಸೆಲ್ ಕೆಲಸದ ಪ್ರಮಾಣವನ್ನು ಮಾತ್ರ ಪರಿಗಣಿಸಿದರೆ, ಹೊಸ ಕೆಲಸದ ವ್ಯಾಪ್ತಿ ಹೀಗಿರುತ್ತದೆ:

ಇಲ್ಲಿ ಎಂದರೆ ಪ್ರಸ್ತುತ screen‌ನಲ್ಲಿ ನೇ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ನ axis-aligned bounding-box area. Render encoder‌ಗಳ ಸಂಖ್ಯೆ ಕಡಿಮೆಯಾಗಿಲ್ಲ; ಆದರೆ ಪ್ರತಿಯೊಂದು clear ಮತ್ತು composite ಈಗ ಸ್ಟ್ರೋಕ್‌ನ screen bounding box ಒಳಗೆ ಸೀಮಿತವಾಗಿದೆ.

ಒಂದೇ ಬಣ್ಣದ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು batch ಮಾಡದ ಕಾರಣ

ಪುಟದಲ್ಲಿರುವ ಬಹುತೇಕ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳು ಒಂದೇ ಬಣ್ಣ ಮತ್ತು density ಹೊಂದಿವೆ. ಆದ್ದರಿಂದ ಡಜನ್‌ಗಟ್ಟಲೆ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು ಒಂದೇ ಬಾರಿಗೆ scratch‌ಗೆ ಚಿತ್ರಿಸಿ ಒಮ್ಮೆ ಮಾತ್ರ composite ಮಾಡಬೇಕೆನಿಸುತ್ತದೆ. ಇದರಿಂದ render passes ಇನ್ನಷ್ಟು ಕಡಿಮೆಯಾಗುತ್ತವೆ, ಆದರೆ overlap ಪ್ರದೇಶಗಳಲ್ಲಿ ಬಣ್ಣ ಮತ್ತು grain‌ನ ಅರ್ಥ ಬದಲಾಗುತ್ತದೆ.

ಉದ್ದೇಶಪೂರ್ವಕವಾಗಿ ಸರಳೀಕರಿಸಿದ ಉದಾಹರಣೆಯನ್ನು ಪರಿಗಣಿಸಿ: ಒಂದು ಪಿಕ್ಸೆಲ್‌ನಲ್ಲಿ ಎರಡು ಸ್ಟ್ರೋಕ್‌ಗಳು ಒಂದೇ grain-gate ಮೌಲ್ಯ ಹಂಚಿಕೊಂಡಿವೆ; ಅವುಗಳ body coverages ಮತ್ತು . ನಿಜವಾದ shader‌ನಲ್ಲಿ gate ಪ್ರತಿ stroke‌ನ pressure depth ಮೇಲೂ ಅವಲಂಬಿತವಾಗಿರುತ್ತದೆ; batching ಸಾಮಾನ್ಯವಾಗಿ equivalent ಅಲ್ಲ ಎಂಬುದನ್ನು ತೋರಿಸಲು ಈ ಇನ್ನಷ್ಟು ಸರಳವಾದ ಉದಾಹರಣೆಯೇ ಸಾಕು. ಪ್ರಸ್ತುತ per-stroke compositing ನೀಡುವುದು

ಆದರೆ ಮೊದಲು bodies ಅನ್ನು merge ಮಾಡಿ ನಂತರ ಒಂದೇ gate ಅನ್ವಯಿಸಿದರೆ ಸಿಗುವುದು

ವ್ಯತ್ಯಾಸ . ಎರಡು ಸ್ಟ್ರೋಕ್‌ಗಳು overlap ಆಗಿ grain gate ಸಂಪೂರ್ಣ ಶೂನ್ಯವೂ ಅಲ್ಲ, ಸಂಪೂರ್ಣ ಒಂದೂ ಅಲ್ಲದಿದ್ದಾಗಲೆಲ್ಲಾ ಫಲಿತಾಂಶ ಬದಲಾಗುತ್ತದೆ. ನೇರವಾಗಿ batch ಮಾಡಿದರೆ crossings‌ನಲ್ಲಿ ಚಾಕ್ ಪುಡಿ ಬೀಳುವ ವಿಧಾನ ಬದಲಾಗುತ್ತದೆ.

ನಿಖರವಾದ batching‌ಗೆ ಸ್ಟ್ರೋಕ್ ಪಿಕ್ಸೆಲ್‌ಗಳು ಪರಸ್ಪರ ಒಂದರ ಮೇಲೊಂದು ಬೀಳುವುದಿಲ್ಲ ಎಂದು ಸಾಬೀತುಪಡಿಸಬೇಕು, ಅಥವಾ ಪ್ರತಿಯೊಂದು ಸ್ಟ್ರೋಕ್‌ಗೆ ಸ್ವತಂತ್ರ atlas ಪ್ರದೇಶವನ್ನು allocate ಮಾಡಿ ಮೂಲ ಕ್ರಮದಲ್ಲೇ composite ಮಾಡಬೇಕು. ಅಂತಿಮ device acceptance scissor ವಿಧಾನವನ್ನು ಉಳಿಸಿಕೊಂಡಿತು; ಆದ್ದರಿಂದ ಈ ಹಂತದಲ್ಲಿ atlas ಅಥವಾ ಅದರ ನಿರ್ವಹಣೆಯ ಸಂಕೀರ್ಣತೆಯನ್ನು ಸೇರಿಸಲಿಲ್ಲ.

ಒಂದು ಬಿಲಿಯನ್ ಪಿಕ್ಸೆಲ್‌ಗಳಿಂದ ಮತ್ತೆ ಕೆಲವು ಮಿಲಿಯನ್‌ಗಳಿಗೆ

ಅಂತಿಮ device ಅಳತೆಗಳು:

ಸಂದರ್ಭತಿದ್ದುಪಡಿಯ ಮೊದಲುನಿಖರ scissor
ಕಾಣುವ 70 ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳು, 300% ಜೂಮ್, ಬರೆಯುವಾಗGPU 52–60 ms≈ 9–10 ms
≈ 121 ಕಾಣುವ ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳು, 300% ಜೂಮ್GPU 77–80 ms13.7–15.6 ms
ಪ್ರತಿ ಫ್ರೇಮ್‌ನ ಸೈದ್ಧಾಂತಿಕ rectangle scope (scratch + composite)783 M–1.34 B ಪಿಕ್ಸೆಲ್‌ಗಳು≈ 1.7 M–3 M ಪಿಕ್ಸೆಲ್‌ಗಳು

Device document‌ನ 3,452 ಸ್ಟ್ರೋಕ್‌ಗಳು ಮತ್ತು 202,710 sample points ಬಳಸಿ clipping bounds‌ನ್ನೂ ಪರಿಶೀಲಿಸಿದೆವು. 0.5×, 1×, 2×, 3×, 5× ಮತ್ತು 8× ಜೂಮ್‌ನಲ್ಲಿ 186,408 viewport cases ರಚಿಸಲಾಯಿತು; non-zero coverage ಉತ್ಪಾದಿಸಬಹುದಾದ ಪ್ರತಿಯೊಂದು point sprite ಲೆಕ್ಕಿಸಿದ scissor ಒಳಗಿತ್ತು. ಈ ಪರಿಶೀಲನೆಯು canvas edges, viewport edges ಮತ್ತು offset‌ನ ವಿವಿಧ ಸಂಯೋಜನೆಗಳನ್ನು ಒಳಗೊಂಡಿತ್ತು.

ಅಂತಿಮ code interaction state ಆಧರಿಸಿ low-resolution LODಗೆ ಬದಲಾಗುವುದಿಲ್ಲ. ಕಡಿಮೆ ಜೂಮ್ ಮಟ್ಟಗಳಲ್ಲಿ ಇನ್ನೂ ಸಂಪೂರ್ಣ ಪುಟದ ink texture ಕಾಣಿಸುತ್ತದೆ; ಹೆಚ್ಚಿನ ಜೂಮ್ ಮಟ್ಟಗಳಲ್ಲಿ ಕಾಣುವ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು vectors ಆಗಿ ಮರು-ರೆಂಡರ್ ಮಾಡಲಾಗುತ್ತದೆ. threshold‌ನ ಒಂದೇ ಬದಿಯಲ್ಲಿ, ಪೆನ್ ಕೆಳಗಿಡುವುದೂ ಪ್ಯಾನ್ ಮಾಡುವುದೂ ಈಗಿರುವ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನು ಬೇರೆ clarity level‌ನಿಂದ ಬದಲಿಸುವುದಿಲ್ಲ. ಹೆಚ್ಚಿನ-ಜೂಮ್ vector redraw ಸಮಯದಲ್ಲಿ ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ನ scratch clear ಮತ್ತು composite ಅದರ ಸ್ವಂತ screen bounding box‌ನ್ನು ಮಾತ್ರ ಆವರಿಸುತ್ತದೆ.

GPU ಸಮಯವು ಸ್ಪಷ್ಟತೆಯನ್ನು ದಾಖಲಿಸಲಿಲ್ಲ

GPU ಕಾರ್ಯಕ್ಷಮತಾ ಸಮಸ್ಯೆಗಳು data structure‌ನಲ್ಲಿ ಅತ್ಯಂತ ಗಮನ ಸೆಳೆಯುವ ಪ್ರಮಾಣದೊಂದಿಗೆ ಅನಿವಾರ್ಯವಾಗಿ ಹೆಚ್ಚಾಗುವುದಿಲ್ಲ. ಈ ಸಂದರ್ಭದಲ್ಲಿ 3,571 input points ಸುಲಭವಾಗಿ ಶಂಕಿಸಬಹುದಾದವು; frame time ಅನ್ನು ನಿರ್ಧರಿಸಿದ್ದು 70 ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ಗಳ ಪ್ರತಿಯೊಂದೂ ಉಂಟುಮಾಡಿದ ಪೂರ್ಣ-ಪರದೆ ಕೆಲಸ ಮತ್ತು ಅವುಗಳ render-pass switching.

ದೃಶ್ಯ ಅರ್ಥವೂ ಲಭ್ಯವಿದ್ದ optimizations ಅನ್ನು ಮಿತಿಗೊಳಿಸಿತು. ಪ್ರತಿ-ಸ್ಟ್ರೋಕ್ scratch, ಮೂಲ compositing order ಮತ್ತು absolute canvas grain coordinates ಅನ್ನು ಮನಬಂದಂತೆ ತೆಗೆದುಹಾಕಲು ಸಾಧ್ಯವಿರಲಿಲ್ಲ. ಒಂದೇ ಬಣ್ಣ ಮತ್ತು ಒಂದೇ density ಎಂದರೆ parameters ಒಂದೇ ಎಂಬುದಷ್ಟೇ — overlap ಆದ ಫಲಿತಾಂಶಗಳನ್ನು merge ಮಾಡಬಹುದು ಎಂದು ಅದು ಸಾಬೀತುಪಡಿಸುವುದಿಲ್ಲ.

ನೈಜ device‌ನ ಪ್ರತಿಕ್ರಿಯೆ ಕಡಿಮೆ GPU time ಹೊಂದಿದ್ದ version ಅನ್ನು ತಿರಸ್ಕರಿಸಿತು. “ಇಡೀ canvas ಮಸುಕಾಗುತ್ತದೆ” ಎಂಬ ಮಾತು ಮಾಪನ ಮಾತ್ರ ತೋರಿಸದ product constraint ಅನ್ನು ಸ್ಪಷ್ಟಪಡಿಸಿತು: Apple Pencil ಪರದೆಯನ್ನು ತಾಕುವಾಗ ಬಳಕೆದಾರರು ಈಗಿರುವ ಸ್ಟ್ರೋಕ್‌ಗಳನ್ನೂ ನೋಡುತ್ತಿದ್ದಾರೆ.

ಅಂತಿಮ version ಯಾವುದೇ ಹೊಸ interaction cache layer ಅನ್ನು ಪರಿಚಯಿಸುವುದಿಲ್ಲ ಮತ್ತು clarity ಕಡಿಮೆ ಮಾಡುವುದಿಲ್ಲ. ಹೆಚ್ಚಿನ-ಜೂಮ್ vector redraw ಪ್ರತಿಯೊಂದು ಚಾಕ್ ಸ್ಟ್ರೋಕ್‌ನ ಕೆಲಸವನ್ನು ಅದರ ಸ್ವಂತ screen bounding box‌ಗೆ ಮಾತ್ರ ಸೀಮಿತಗೊಳಿಸುತ್ತದೆ. LucasPad‌ಗೆ ಮತ್ತೆ load ಮಾಡಿದ ನಂತರ feedback ಹೀಗಿತ್ತು: “ತುಂಬಾ ಚೆನ್ನಾಗಿದೆ.”