Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
お絵かきツールのパフォーマンスチューニング
Search
nontan-rh
April 14, 2017
Programming
2.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
お絵かきツールのパフォーマンスチューニング
pixiv Sketch WebGLお絵かき機能のざっくりとしたチューニングの話
nontan-rh
April 14, 2017
More Decks by nontan-rh
See All by nontan-rh
VRoidキャラメイクシステム 完全解説
nontan
1
2.3k
Other Decks in Programming
See All in Programming
symfony/aiとlaravel/boost
77web
0
110
技術的負債解消で開発者の未来を開く- AIの力でコード刷新
kmd2kmd
0
140
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
1k
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
Go1.27で導入されるジェネリクスメソッドでできること
mackee
0
230
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
430
Oxcを導入して開発体験が向上した話
yug1224
4
370
The Bowling Game- From Imperative to Functional Programming - Part 1
philipschwarz
PRO
0
220
dRuby over BLE
makicamel
2
400
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
230
SLOをサービス品質の共通言語にするために 取り組んできたこと
wakana0222
0
270
Featured
See All Featured
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
270
AI: The stuff that nobody shows you
jnunemaker
PRO
8
760
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
180
Abbi's Birthday
coloredviolet
3
8.4k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
220
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.8k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.9k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
660
Transcript
お絵かきツールの パフォーマンスチューニング ~ 60FPSのために ~
自己紹介 • 名前: 磯崎 希 (のんたん) • 職業: アルバイト •
出身: ネイティブ畑 ◦ C++, Swift, など... ◦ Javascript歴は2ヶ月くらいです • 仕事内容: iOS, Android, Webのお絵かき機能を担当しています ◦ OpenGLまわりをゴリゴリやってます
今回の内容 • pixiv Sketchのお絵かき機能の総合的なパフォーマンス改善の話をします ◦ WebGLだけじゃないです • 改善例を列挙します • 基本的な話が多いです
準備
パフォーマンス改善の手順 1. ちゃんと測る 2. ちゃんとボトルネックを潰す 3. 1.に戻る
パフォーマンス改善の手順(つづき) • 「ちゃんと測る」がとても難しい ◦ クロック周波数が変化する ◦ 裏のプロセスの状況によって変化する ◦ 手でドローの情報を入力するのでムラがある ◦
ブラウザが起動してからどれくらい時間が経ったかでムラがある ◦ 何回も測って平均を取るべき ◦ 改善したかどうか検定するべき
パフォーマンスの指標 • FPSで評価するわけではない ◦ マウスイベントが入ってきたタイミングで処理をしている ◦ お絵かきツールでフレーム落ちは末期的 ◦ フレーム落ちが存在しているかどうかだけ見る •
代わりに1フレーム当たり処理時間の割合を見る ◦ 改善目的の処理が他の主要な処理の何 %の時間を要しているか
パフォーマンスの指標(Chromeの場合 その1)
パフォーマンスの指標(Chromeの場合 その2)
パフォーマンスの指標(Edgeの場合 その1)
パフォーマンスの指標(Edgeの場合 その2)
実例
GCが......? • ブラウザによって差が大きいが......
ストロークデータ生成(before) const BSplineCurve = { refine: (points: [number, number][]): [number,
number][] => { const refined = []; if (points.length - 1 >= 1) { for (let i = 1; i <= points.length - 1; i++) { refined .push(points[i - 1]); refined .push([(points[i - 1][0] + points[i][0]) * 0.5, (points[i - 1][1] + points[i][1]) * 0.5]); } } if (points.length > 0) { refined.push(points[points.length - 1]); } return refined; }, };
ストロークデータ生成(after) const BSplineCurve = { refine: (dst: number[], src: number[],
num): void => { for (let i = 1; i <= num - 1; i++) { const srcBase = (i - 1) * 2; const dstBase = (i - 1) * 4; dst[dstBase + 0] = src[srcBase]; dst[dstBase + 1] = src[srcBase + 1]; dst[dstBase + 2] = (src[srcBase] + src[srcBase + 2]) * 0.5; dst[dstBase + 3] = (src[srcBase + 1] + src[srcBase + 3]) * 0.5; } dst[(num - 1) * 4] = src[(num - 1) * 2]; dst[((num - 1) * 4) + 1] = src[((num - 1) * 2) + 1]; return ((num - 1) * 2) + 1; }, };
ストロークデータ生成(結果)
レイヤー合成が......?
レイヤー合成範囲 • 線を引いている途中、1フレームの間に変化している部分は一部のみ • 具体的には線の先っぽのみ
レイヤー合成範囲 • 変更があり得る場所だけを更新すれば良い • 更新範囲を覆う縦横が水平垂直の矩形を算出して、その部分だけ更新する
レイヤー合成範囲(補足) • B-スプライン曲線は凸包性がある ◦ 曲線は曲線を作るのに用いた制御点の凸包に収まる • 合成範囲は各制御点のx, yそれぞれの最小、最大を求めるだけで計算できる
レイヤー合成範囲(コード) // dirtyRect: 更新すべき矩形 gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([ dirtyRect.left,
dirtyRect.top, dirtyRect.right, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, dirtyRect.left, dirtyRect.bottom, ]), gl.DYNAMIC_DRAW); gl.enableVertexAttribArray (this.vertexLocation ); gl.vertexAttribPointer (this.vertexLocation , 2, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
gl.bufferData, gl.bufferSubDataが重い...... • 前に述べた矩形(dirtyRect)の転送
Uniform化 // 初期化(一回だけ走る) const rect = new Float32Array([0, 0, 0,
1, 1, 1, 1, 0]); gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, rect, gl.STATIC_DRAW); // 描画 gl.uniform4f(dirtyRectLocation , dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); // シェーダ(vertex shader) attribute vec2 inVertex ; uniform vec4 dirtyRect ; gl_Position = vec4((vec2(1.) - inVertex) * dirtyRect.xy + inVertex * dirtyRect.zw, 0., 1.);
レイヤー合成最適化の結果
gl.readPixels, IOは重い...... • Sketchで扱うデータはindexedDBに自動保存される ◦ 細かいストロークを連続したときに問題に
バックアップを遅延させる • ストロークが終わってから1秒間バックアップを遅延させる ◦ 1秒間の間に次のストロークが始まったらバックアップをキャンセル ◦ 次のストロークに関しても同様に
バックアップを遅延させる(コード) class BackupScheduler { schedule = () => { if
(this.timeoutId) { clearTimeout (this.timeoutId); this.timeoutId = null; } this.timeoutId = setTimeout(() => { if (this.isDrawing) { this.timeoutId = null; return; } // gl.readPixels(...); // indexedDBに保存 }, 1000); }; }
バックアップを遅延させる(結果)
グラフが紫色に...... • 内訳は「レンダリング」 ◦ WebGLでのレンダリングの時間ではなく、ブラウザ側の再描画の時間
グラフが紫色に...... • 原因はcanvasにメニューが覆いかぶさっていたこと ◦ 下のcanvasが再描画されると、その上にかかっている要素に再描画フラグが立つ (?) • メニューとcanvasの重なりをなくして改善
結果(Edge)
結果(Chrome)
描き出しが重い......
ReactのsetStateが重かった • ブラウザによって差が大きい • ストローク中はsetStateを呼ばないようにする ◦ Reactに頼らない ◦ どうしても使いたければ、 setStateをストロークの終わりまで遅延させる
以上です 御清聴ありがとうございました