描画 1 フレームの内訳:
[PERF][DRAW] head=1tick imgprep=0tick paint=304tick bgimg=35tick grad=112tick border=0tick
[PERF][DRAW] head=1tick imgprep=0tick paint=302tick bgimg=33tick grad=116tick border=0tick
グラデーションが単独で最大の要素。
draw_linear_gradient は 1
ピクセルごとに:
p = x·dx + y·dy を計算t = (p - min_proj) / lengthsample_gradient_stops(stops, t) —
ストップ配列を線形走査し、 4 チャンネルを浮動小数で補間draw_pixel_alphaヒーロー領域が 924×600 なら 55 万回これを回す。
t
から色への写像はピクセル位置に依存しない。
グラデーション軸方向の長さ length ぶんの LUT を先に作れば、
sample_gradient_stops(ストップ走査+浮動小数補間)の呼び出しは
W×H 回から length 回へ落ちる。
LUT の分解能は ceil(length) 段とする。これは
グラデーション軸方向の 1 ピクセルに 1
段を割り当てる意味で、
dx == 0(0deg / 180deg)なら t は
y だけの関数。 1
行が単色になるので、行ごとに boxfill 1 回で済む。
dy == 0(90deg / 270deg)なら列方向に同じことが言える
(ただしフレームバッファは行優先なので、行内を走査して
同色の連続区間をまとめる形にする)。
これで 55 万回のピクセル演算が数百回の矩形塗りになる。
web_engine/gradient_lut.rs(純粋・no_std・グローバル状態なし)
/// LUT の段数を決める。length は射影長(ピクセル)。
pub fn lut_size(length: f32) -> usize;
/// t(0.0-1.0 想定、範囲外はクランプ)を LUT の添字へ。
pub fn lut_index(t: f32, size: usize) -> usize;
/// dx, dy から軸平行かどうかを判定する。
pub enum Axis { Vertical, Horizontal, Diagonal }
pub fn classify_axis(dx: f32, dy: f32) -> Axis; grad
修正前 112 tick
修正後 62〜70 tick
約 43% 短縮(make test 744
件パス、test_gradient_lut 24 件を新規追加)。
実測の下がり幅から見て、効果はほぼ O-1(LUT 化)によるもの。 このサイトのグラデーションは 135deg 等の斜めが主で、 O-2(軸平行の行一括塗り)の経路にはほとんど入っていない。
O-2 は縦(0/180deg)グラデーションのあるページでは大きく効くはずだが、 このページでは確認できていない。効いたと書かないこと。
paint 約 300 tick のうち: - グラデーション 65 tick(22%) - 背景画像 38 tick(13%) - 残り約 200 tick(65%)は未特定
次はテキスト描画と矩形塗りを分けて測る。