const imageData = context.getImageData(0, 0, width, height);
if (imageData) {
const { data } = imageData;
for (let y = 0; y < height; ++y) {
for (let x = 0; x < width; ++x) {
const i = width * 4 * y + 4 * x;
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
data[i + 0] = r;
data[i + 1] = g;
data[i + 2] = b;
data[i + 3] = 255;
}
}
context.putImageData(imageData, 0, 0);
}
js 로 대충 이 내용이거든
800 600 픽셀 랜덤 색으로 찍어서 이렇게 나오는 코드임 canvas image data 로
대충 60프레임 나옴
캔버스에 그리는거 wasm 으로 바꾸면 성능 향상 얼마나 있나 보고싶어서
https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm
러스트로 만들어서 했는데
use wasm_bindgen::prelude::*;
use rand::prelude::*;
use rand_distr::{Distribution, Normal, NormalError};
// 1. [u8]
#[wasm_bindgen]
pub fn random_colors(data: &mut [u8], width: u32, height: u32) {
let mut rng = rand::thread_rng();
for y in 0..height {
for x in 0..width {
let i = (width * 4 * y + 4 * x) as usize;
data[((i + 0) as usize)] = rng.gen::<u8>();
data[((i + 1) as usize)] = rng.gen::<u8>();
data[((i + 2) as usize)] = rng.gen::<u8>();
data[((i + 3) as usize)] = 0xff;
}
}
}
// 2. Uint8ClampedArray
#[wasm_bindgen]
pub fn random_colors(data: js_sys::Uint8ClampedArray, width: u32, height: u32) {
let mut rng = rand::thread_rng();
let normal = Normal::new(0.0, 255.0);
for i in 0..width * height * 4 {
// 2-1. set_index (thread_rng::gen)
let v = if i % 4 == 3 { 0xff } else { rng.gen::<u8>() };
data.set_index(i, v);
// 2-2. set_index (normal::sample)
let v = if i % 4 == 3 {
0xff
} else {
normal.expect("REASON").sample(&mut rng) as u8
};
data.set_index(i, v);
}
for i in 0..width * height {
// 2-3. set (Array)
let a: js_sys::Array = js_sys::Array::new_with_length(4);
a.set(0, wasm_bindgen::JsValue::from_f64(rng.gen::<u8>() as f64));
a.set(1, wasm_bindgen::JsValue::from_f64(rng.gen::<u8>() as f64));
a.set(2, wasm_bindgen::JsValue::from_f64(rng.gen::<u8>() as f64));
a.set(3, wasm_bindgen::JsValue::from_f64(0xff as f64));
data.set(&a, i * 4);
// 2-4. set_index (thread_rng::gen)
data.set_index(i * 4 + 0, rng.gen::<u8>());
data.set_index(i * 4 + 1, rng.gen::<u8>());
data.set_index(i * 4 + 2, rng.gen::<u8>());
data.set_index(i * 4 + 3, 0xff);
}
// 2-5. set (Array)
let a: js_sys::Array = js_sys::Array::new_with_length(width * height * 4);
for i in 0..width * height * 4 {
a.set(
i,
wasm_bindgen::JsValue::from_f64(if i % 4 == 3 { 0xff } else { rng.gen::<u8>() } as f64),
);
}
data.set(&a, 0);
}
뭘 어떻게 해도 10~15프레임 나오더라 (1번이 제일 빠름)
병신같이 짠거같은데 조언좀
인수를 바꾸는거보다 새 배열을 반환하는 게 더 빠르지 않을까요? 사실 잘 모르겠어요 저도 궁금해요
Rust 특성 상 1번도 절대 빠를 수 없는데? 인덱스가 크기를 넘는 지 매번 체크해서, 뭔가 잘못 짠 듯. 그리고 확신은 없지만 release로 빌드하면 달라지지 않을까?
1번도 js canvas context image data api 보다 한참 느리더라 기껏해야 15프레임
오 릴리즈 빌드.. 한번 봐야할듯
보니까 wasm-pack은 --debug옵션 주지 않는 이상 기본적으로 릴리즈 빌드 해주네요 글고 제가 해봤을땐 1번으로 해도 js보단 1.2-1.5배정도 속도던데 왜 더 느리게 나왔는진 모르겠음
알쏭달쏭하네
러스트 안해봐서 잘 모르겠는데 Wasm으로 캔버스 성능향삼 힘들다
헉..
1번 width height 받을필요 없잖아 그냥 data.chunks_exact_mut(4)로 4개씩 순회할수 있지 않음?
아니면 아예 rng.fill_bytes()로 바이트 다 채운다음에 data.take(3).skip(4)로 alpha만 255로 덮어쓸수도 있고
근데 저코드만 봐서는 아무리 병신같이 짰다고해도 몇 GB/s 단위는 충분히 넘길텐데 그냥 다른부분에서 병목터진거 아님?
오 꿀팁.. 적용해봄 일단 wasm 도 러스트도 초짜에 대충 기본 세팅으로 한거라 다른 요인이 뭔지도 감이 안잡혀서 겸사겸사 조언얻을겸
오.. fill_bytes 하고 for i in 0..width * height { data[(i * 4 + 3) as usize] = 0xff; } 만 해줘도 엄청 빨라지는데? 45 프레임정도 나오는듯
걍 shader 쓰지..