Dostlar, kafayı yemek üzereydim. Electron tabanlı bir veri görselleştirme uygulamam vardı, kullanıcılar binlerce veri noktasını çizince CPU fanları kalkışa geçiyordu. Canvas 2D API ile yazılmıştı her şey, "optimize ettim" diye kendimi kandırıyordum ama sonuç hep aynı: kırmızı çizgiler ve şikayetler.
Performans Kâbusu ve Çaresizlik
Olay şu: Klasik `canvas.getContext('2d')` ile çizim yapıyordun. Her frame'de, binlerce `arc()` ve `lineTo()` çağrısı. JavaScript motoru ile render işi aynı thread'de. Veri seti büyüdükçe, her şey tıkanıyordu. "Bu iş olmayacak" dedim ve StackOverflow'da gezinirken, bir yorumda "2D canvas için bile WebGL backend'i deneyin" diye bir şey gördüm. Meğerse modern tarayıcılar (ve dolayısıyla Electron) canvas 2D çizimlerini de arka planda WebGL'e çevirip işliyormuş. Ama direkt kontrol bende değil.
WebGL'e Geçiş Macerası
"Direkt WebGL kullanayım bari" dedim. Korkunçtu, OpenGL bilgim sıfıra yakındı. Ama PixiJS gibi bir render kütüphanesi kullanmak istemedim, çok hafif kalmasını istiyordum. Sonunda, sadece nokta ve çizgi çizmek için mini bir WebGL wrapper'ı yazmaya karar verdim. Vertex buffer, shader falan derken iki günüm gitti. Ama sonunda basit bir çizgi çizebildim.
Asıl sihir şurada: Tüm o binlerce noktanın koordinatlarını bir kerede GPU'ya yolluyorsun. Sonra render loop'unda sadece "çiz" komutu veriyorsun. CPU'nun yaptığı iş, sadece veriyi hazırlamak ve GPU'ya "al bunu" demek. Çizimin kendisi GPU'da, tamamen ayrı bir işlemci üzerinde oluyor.
Sonuçlar ve Şaşkınlık
Değişikliği yapıp uygulamayı çalıştırdığımda, performans monitorüne baktım ve gözlerime inanamadım. Aynı veri setiyle, eski yöntemde CPU %85-95 arası geziniyorken, WebGL versiyonunda bu oran %20-30'a düştü! GPU kullanımı ise sadece %10-15 arttı. Kullanıcı arayüzü artık butter gibi akıyor, zoom/pan yaparken hiç takılma yok. Olay bu kadar basitmiş meğer: Çizim işini CPU'dan al, GPU'ya ver.
Tabii her şey güllük gülistanlık değil. WebGL kodu yazmak, debug etmek canvas 2D'ye göre katbekat zor. Bir nokta yanlış yerdeyse, ekran simsiyah kalıyor. Ama öğrendikten sonra, özellikle çok fazla primitive (nokta, çizgi, basit şekil) çizmen gereken veri görselleştirme projelerinde, kesinlikle ilk tercih olmalı.
Siz de benzer bir performans duvarına tosladınız mı? Canvas 2D'de takılıp kalmak mı daha maliyetli, yoksa WebGL'in dik yokuşuna tırmanmak mı? Ya da PixiJS, Three.js gibi kütüphanelerle bu iş daha mı kolay hallolur?
Olay şu: Klasik `canvas.getContext('2d')` ile çizim yapıyordun. Her frame'de, binlerce `arc()` ve `lineTo()` çağrısı. JavaScript motoru ile render işi aynı thread'de. Veri seti büyüdükçe, her şey tıkanıyordu. "Bu iş olmayacak" dedim ve StackOverflow'da gezinirken, bir yorumda "2D canvas için bile WebGL backend'i deneyin" diye bir şey gördüm. Meğerse modern tarayıcılar (ve dolayısıyla Electron) canvas 2D çizimlerini de arka planda WebGL'e çevirip işliyormuş. Ama direkt kontrol bende değil.
"Direkt WebGL kullanayım bari" dedim. Korkunçtu, OpenGL bilgim sıfıra yakındı. Ama PixiJS gibi bir render kütüphanesi kullanmak istemedim, çok hafif kalmasını istiyordum. Sonunda, sadece nokta ve çizgi çizmek için mini bir WebGL wrapper'ı yazmaya karar verdim. Vertex buffer, shader falan derken iki günüm gitti. Ama sonunda basit bir çizgi çizebildim.
Asıl sihir şurada: Tüm o binlerce noktanın koordinatlarını bir kerede GPU'ya yolluyorsun. Sonra render loop'unda sadece "çiz" komutu veriyorsun. CPU'nun yaptığı iş, sadece veriyi hazırlamak ve GPU'ya "al bunu" demek. Çizimin kendisi GPU'da, tamamen ayrı bir işlemci üzerinde oluyor.
JavaScript:
// Eskisi (Canvas 2D - CPU Ağır)
for (let point of dataPoints) {
ctx.beginPath();
ctx.arc(point.x, point.y, 2, 0, Math.PI 2);
ctx.fill();
}
// Yenisi (WebGL - GPU'ya Yükle & Çiz)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(allPoints), gl.STATIC_DRAW);
gl.drawArrays(gl.POINTS, 0, allPoints.length / 2);
Değişikliği yapıp uygulamayı çalıştırdığımda, performans monitorüne baktım ve gözlerime inanamadım. Aynı veri setiyle, eski yöntemde CPU %85-95 arası geziniyorken, WebGL versiyonunda bu oran %20-30'a düştü! GPU kullanımı ise sadece %10-15 arttı. Kullanıcı arayüzü artık butter gibi akıyor, zoom/pan yaparken hiç takılma yok. Olay bu kadar basitmiş meğer: Çizim işini CPU'dan al, GPU'ya ver.
Tabii her şey güllük gülistanlık değil. WebGL kodu yazmak, debug etmek canvas 2D'ye göre katbekat zor. Bir nokta yanlış yerdeyse, ekran simsiyah kalıyor. Ama öğrendikten sonra, özellikle çok fazla primitive (nokta, çizgi, basit şekil) çizmen gereken veri görselleştirme projelerinde, kesinlikle ilk tercih olmalı.
Siz de benzer bir performans duvarına tosladınız mı? Canvas 2D'de takılıp kalmak mı daha maliyetli, yoksa WebGL'in dik yokuşuna tırmanmak mı? Ya da PixiJS, Three.js gibi kütüphanelerle bu iş daha mı kolay hallolur?