Yayınlanma tarihi: 20 Temmuz 2023, Son güncelleme tarihi: 27 Ağustos 2025
Web geliştiricileri için WebGPU, GPU'lara birleşik ve hızlı erişim sağlayan bir web grafikleri API'sidir. WebGPU, modern donanım özelliklerini kullanıma sunar ve Direct3D 12, Metal ve Vulkan'a benzer şekilde GPU'da oluşturma ve hesaplama işlemlerine olanak tanır.
Bu hikaye doğru olsa da eksik. WebGPU, Apple, Google, Intel, Mozilla ve Microsoft gibi büyük şirketlerin işbirliğiyle geliştirilmiştir. Bu kişiler arasında, WebGPU'nun bir JavaScript API'sinden daha fazlası olabileceğini, web dışındaki ekosistemlerdeki geliştiriciler için platformlar arası bir grafik API'si olabileceğini fark edenler de vardı.
Birincil kullanım alanını karşılamak için Chrome 113'te bir JavaScript API'si kullanıma sunuldu. Ancak bununla birlikte başka bir önemli proje daha geliştirildi: webgpu.h C API'si. Bu C başlık dosyasında, WebGPU'nun tüm kullanılabilir prosedürleri ve veri yapıları listelenir. Platformdan bağımsız bir donanım soyutlama katmanı olarak işlev görür. Farklı platformlarda tutarlı bir arayüz sağlayarak platforma özel uygulamalar oluşturmanıza olanak tanır.
Bu belgede, hem web'de hem de belirli platformlarda çalışan, WebGPU kullanan küçük bir C++ uygulaması yazmayı öğreneceksiniz. Kod tabanınızda minimum ayarlamalarla tarayıcı penceresinde ve masaüstü penceresinde görünen kırmızı üçgeni alırsınız.

İşleyiş şekli
Tamamlanmış uygulamayı görmek için WebGPU platformlar arası uygulama deposuna göz atın.
Bu uygulama, tek bir kod tabanından masaüstü ve web uygulamaları oluşturmak için WebGPU'nun nasıl kullanılacağını gösteren minimalist bir C++ örneğidir. Bu kitaplık, webgpu_cpp.h adlı bir C++ sarmalayıcısı aracılığıyla platformdan bağımsız bir donanım soyutlama katmanı olarak WebGPU'nun webgpu.h dosyasını kullanır.
Web'de uygulama, JavaScript API'sinin üzerinde webgpu.h'yi uygulayan bağlamalara sahip emdawnwebgpu (Emscripten Dawn WebGPU) kullanılarak oluşturulur. macOS veya Windows gibi belirli platformlarda bu proje, Chromium'un platformlar arası WebGPU uygulaması olan Dawn'a karşı oluşturulabilir. webgpu.h'nin Rust uygulaması olan wgpu-native'in de mevcut olduğunu ancak bu dokümanda kullanılmadığını belirtmek isteriz.
Başlayın
Başlamak için, platformlar arası derlemeleri standart bir şekilde işlemek üzere bir C++ derleyicisine ve CMake'e ihtiyacınız vardır. Özel bir klasörde main.cpp
kaynak dosyası ve CMakeLists.txt
derleme dosyası oluşturun.
main.cpp
dosyası şu an için boş bir main()
işlevi içermelidir.
int main() {}
CMakeLists.txt
dosyası, proje hakkında temel bilgiler içerir. Son satırda, yürütülebilir dosyanın adının "app" ve kaynak kodunun main.cpp
olduğu belirtiliyor.
cmake_minimum_required(VERSION 3.22) # CMake version check
project(app) # Create project "app"
set(CMAKE_CXX_STANDARD 20) # Enable C++20 standard
add_executable(app "main.cpp")
"build/" alt klasöründe derleme dosyaları oluşturmak için cmake -B build
, uygulamayı gerçekten derlemek ve yürütülebilir dosyayı oluşturmak için cmake --build build
komutunu çalıştırın.
# Build the app with CMake.
$ cmake -B build && cmake --build build
# Run the app.
$ ./build/app
Uygulama çalışır ancak ekranda bir şeyler çizmek için bir yol bulmanız gerektiğinden henüz bir çıkış yoktur.
Get Dawn
Üçgeninizi çizmek için Chromium'un platformlar arası WebGPU uygulaması olan Dawn'dan yararlanabilirsiniz. Buna, ekrana çizim yapmak için kullanılan GLFW C++ kitaplığı da dahildir. Dawn'u indirmenin bir yolu, onu deponuza git alt modülü olarak eklemektir. Aşağıdaki komutlar, dosyayı "dawn/" alt klasörüne getirir.
$ git init
$ git submodule add https://dawn.googlesource.com/dawn
Ardından, CMakeLists.txt
dosyasına aşağıdaki şekilde ekleyin:
- CMake
DAWN_FETCH_DEPENDENCIES
seçeneği, tüm Dawn bağımlılarını getirir. - CMake
DAWN_BUILD_MONOLITHIC_LIBRARY
seçeneği, tüm Dawn bileşenlerini tek bir kitaplıkta toplar. dawn/
alt klasörü hedefe dahil edilir.- Uygulamanız,
webgpu_dawn
,webgpu_glfw
veglfw
hedeflerine bağlı olacaktır. Böylece bunları daha sonramain.cpp
dosyasında kullanabilirsiniz.
…
set(DAWN_FETCH_DEPENDENCIES ON)
set(DAWN_BUILD_MONOLITHIC_LIBRARY STATIC)
add_subdirectory("dawn" EXCLUDE_FROM_ALL)
target_link_libraries(app PRIVATE webgpu_dawn webgpu_glfw glfw)
Pencere açma
Dawn kullanıma sunulduğundan beri ekranda çizim yapmak için GLFW kullanılıyor. Kolaylık sağlamak için webgpu_glfw
'da yer alan bu kitaplık, pencere yönetimi için platformdan bağımsız kod yazmanıza olanak tanır.
512x512 çözünürlüğe sahip "WebGPU penceresi" adlı bir pencere açmak için main.cpp
dosyasını aşağıdaki gibi güncelleyin. Burada glfwWindowHint()
'nın belirli bir grafik API'si başlatma isteğinde bulunmamak için kullanıldığını unutmayın.
#include <GLFW/glfw3.h>
const uint32_t kWidth = 512;
const uint32_t kHeight = 512;
void Start() {
if (!glfwInit()) {
return;
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window =
glfwCreateWindow(kWidth, kHeight, "WebGPU window", nullptr, nullptr);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
// TODO: Render a triangle using WebGPU.
}
}
int main() {
Start();
}
Uygulamayı yeniden oluşturup eskisi gibi çalıştırmak artık boş bir pencereyle sonuçlanıyor. İlerleme kaydediyorsunuz.

GPU cihazı edinme
JavaScript'te navigator.gpu
, GPU'ya erişmek için giriş noktanızdır. C++'ta aynı amaçla kullanılan bir wgpu::Instance
değişkenini manuel olarak oluşturmanız gerekir. Kolaylık sağlamak için instance
öğesini main.cpp
dosyasının en üstünde bildirin ve wgpu::CreateInstance()
öğesini Init()
içinde çağırın.
#include <webgpu/webgpu_cpp.h>
…
wgpu::Instance instance;
…
void Init() {
static const auto kTimedWaitAny = wgpu::InstanceFeatureName::TimedWaitAny;
wgpu::InstanceDescriptor instanceDesc{.requiredFeatureCount = 1,
.requiredFeatures = &kTimedWaitAny};
instance = wgpu::CreateInstance(&instanceDesc);
}
int main() {
Init();
Start();
}
main.cpp
dosyasının en üstünde iki değişken wgpu::Adapter
ve wgpu::Device
bildirin. Init()
işlevini instance.RequestAdapter()
işlevini çağıracak ve sonuç geri çağırmasını adapter
işlevine atayacak şekilde güncelleyin. Ardından adapter.RequestDevice()
işlevini çağırın ve sonuç geri çağırmasını device
işlevine atayın.
#include <iostream>
#include <dawn/webgpu_cpp_print.h>
…
wgpu::Adapter adapter;
wgpu::Device device;
void Init() {
…
wgpu::Future f1 = instance.RequestAdapter(
nullptr, wgpu::CallbackMode::WaitAnyOnly,
[](wgpu::RequestAdapterStatus status, wgpu::Adapter a,
wgpu::StringView message) {
if (status != wgpu::RequestAdapterStatus::Success) {
std::cout << "RequestAdapter: " << message << "\n";
exit(0);
}
adapter = std::move(a);
});
instance.WaitAny(f1, UINT64_MAX);
wgpu::DeviceDescriptor desc{};
desc.SetUncapturedErrorCallback([](const wgpu::Device&,
wgpu::ErrorType errorType,
wgpu::StringView message) {
std::cout << "Error: " << errorType << " - message: " << message << "\n";
});
wgpu::Future f2 = adapter.RequestDevice(
&desc, wgpu::CallbackMode::WaitAnyOnly,
[](wgpu::RequestDeviceStatus status, wgpu::Device d,
wgpu::StringView message) {
if (status != wgpu::RequestDeviceStatus::Success) {
std::cout << "RequestDevice: " << message << "\n";
exit(0);
}
device = std::move(d);
});
instance.WaitAny(f2, UINT64_MAX);
}
Üçgen çizme
Tarayıcı bu işlemi gerçekleştirdiğinden takas zinciri, JavaScript API'sinde kullanıma sunulmaz. C++'ta bunu manuel olarak oluşturmanız gerekir. Kolaylık sağlaması için main.cpp
dosyasının en üstünde wgpu::Surface
değişkenini tekrar tanımlayın. Start()
içinde GLFW penceresini oluşturduktan hemen sonra, wgpu::Surface
(HTML tuvaline benzer) oluşturmak için kullanışlı wgpu::glfw::CreateSurfaceForWindow()
işlevini çağırın ve InitGraphics()
içinde yeni yardımcı ConfigureSurface()
işlevini çağırarak yapılandırın. Ayrıca, while döngüsünde bir sonraki dokuyu göstermek için surface.Present()
işlevini de çağırmanız gerekir. Henüz oluşturma işlemi yapılmadığından bu durumun görünür bir etkisi yoktur.
#include <webgpu/webgpu_glfw.h>
…
wgpu::Surface surface;
wgpu::TextureFormat format;
void ConfigureSurface() {
wgpu::SurfaceCapabilities capabilities;
surface.GetCapabilities(adapter, &capabilities);
format = capabilities.formats[0];
wgpu::SurfaceConfiguration config{.device = device,
.format = format,
.width = kWidth,
.height = kHeight,
.presentMode = wgpu::PresentMode::Fifo};
surface.Configure(&config);
}
void InitGraphics() {
ConfigureSurface();
}
void Render() {
// TODO: Render a triangle using WebGPU.
}
void Start() {
…
surface = wgpu::glfw::CreateSurfaceForWindow(instance, window);
InitGraphics();
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
Render();
surface.Present();
instance.ProcessEvents();
}
}
Aşağıdaki kodu kullanarak oluşturma ardışık düzenini oluşturmak için uygun bir zaman. Daha kolay erişim için main.cpp
dosyasının en üstünde bir wgpu::RenderPipeline
değişkeni tanımlayın ve InitGraphics()
içinde CreateRenderPipeline()
yardımcı işlevini çağırın.
wgpu::RenderPipeline pipeline; … const char shaderCode[] = R"( @vertex fn vertexMain(@builtin(vertex_index) i : u32) -> @builtin(position) vec4f { const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1)); return vec4f(pos[i], 0, 1); } @fragment fn fragmentMain() -> @location(0) vec4f { return vec4f(1, 0, 0, 1); } )"; void CreateRenderPipeline() { wgpu::ShaderSourceWGSL wgsl{{.code = shaderCode}}; wgpu::ShaderModuleDescriptor shaderModuleDescriptor{.nextInChain = &wgsl}; wgpu::ShaderModule shaderModule = device.CreateShaderModule(&shaderModuleDescriptor); wgpu::ColorTargetState colorTargetState{.format = format}; wgpu::FragmentState fragmentState{ .module = shaderModule, .targetCount = 1, .targets = &colorTargetState}; wgpu::RenderPipelineDescriptor descriptor{.vertex = {.module = shaderModule}, .fragment = &fragmentState}; pipeline = device.CreateRenderPipeline(&descriptor); } void InitGraphics() { … CreateRenderPipeline(); }
Son olarak, her karede çağrılan Render()
işlevinde GPU'ya oluşturma komutları gönderin.
void Render() {
wgpu::SurfaceTexture surfaceTexture;
surface.GetCurrentTexture(&surfaceTexture);
wgpu::RenderPassColorAttachment attachment{
.view = surfaceTexture.texture.CreateView(),
.loadOp = wgpu::LoadOp::Clear,
.storeOp = wgpu::StoreOp::Store};
wgpu::RenderPassDescriptor renderpass{.colorAttachmentCount = 1,
.colorAttachments = &attachment};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpass);
pass.SetPipeline(pipeline);
pass.Draw(3);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
device.GetQueue().Submit(1, &commands);
}
Uygulamayı CMake ile yeniden oluşturmak ve çalıştırmak artık uzun zamandır beklenen kırmızı üçgenin bir pencerede görünmesine neden oluyor. Mola vermeyi hak ettiniz.

WebAssembly'ye derleme
Şimdi mevcut kod tabanınızı bir tarayıcı penceresinde bu kırmızı üçgeni çizecek şekilde ayarlamak için gereken minimum değişikliklere göz atalım. Uygulama, JavaScript API'sinin üzerinde webgpu.h'yi uygulayan bağlamalara sahip emdawnwebgpu (Emscripten Dawn WebGPU) kullanılarak oluşturulur. C/C++ programlarını WebAssembly'ye derlemek için kullanılan bir araç olan Emscripten'i kullanır.
CMake ayarlarını güncelleme
Emscripten yüklendikten sonra CMakeLists.txt
derleme dosyasını aşağıdaki şekilde güncelleyin.
Yalnızca vurgulanan kodu değiştirmeniz gerekir.
set_target_properties
, hedef dosyaya "html" dosya uzantısını otomatik olarak eklemek için kullanılır. Başka bir deyişle, "app.html" dosyası oluşturursunuz.emdawnwebgpu_cpp
hedef bağlantı kitaplığı, Emscripten'de WebGPU desteğini etkinleştirir. Bu olmadanmain.cpp
dosyanızwebgpu/webgpu_cpp.h
dosyasına erişemez.ASYNCIFY=1
uygulama bağlantısı seçeneği, eşzamanlı C++ kodunun eşzamansız JavaScript ile etkileşim kurmasına olanak tanır.USE_GLFW=3
uygulama bağlantısı seçeneği, Emscripten'e GLFW 3 API'nin yerleşik JavaScript uygulamasını kullanmasını söyler.
cmake_minimum_required(VERSION 3.22) # CMake version check
project(app) # Create project "app"
set(CMAKE_CXX_STANDARD 20) # Enable C++20 standard
add_executable(app "main.cpp")
set(DAWN_FETCH_DEPENDENCIES ON)
set(DAWN_BUILD_MONOLITHIC_LIBRARY STATIC)
add_subdirectory("dawn" EXCLUDE_FROM_ALL)
if(EMSCRIPTEN)
set_target_properties(app PROPERTIES SUFFIX ".html")
target_link_libraries(app PRIVATE emdawnwebgpu_cpp webgpu_glfw)
target_link_options(app PRIVATE "-sASYNCIFY=1" "-sUSE_GLFW=3")
else()
target_link_libraries(app PRIVATE webgpu_dawn webgpu_glfw glfw)
endif()
Kodu güncelleme
While döngüsü kullanmak yerine, emscripten_set_main_loop(Render)
işlevini çağırarak Render()
işlevinin tarayıcı ve monitörle düzgün şekilde eşleşen, uygun ve sorunsuz bir hızda çağrıldığından emin olun.
#include <iostream>
#include <GLFW/glfw3.h>
#if defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#endif
#include <dawn/webgpu_cpp_print.h>
#include <webgpu/webgpu_cpp.h>
#include <webgpu/webgpu_glfw.h>
void Start() {
…
#if defined(__EMSCRIPTEN__)
emscripten_set_main_loop(Render, 0, false);
#else
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
Render();
surface.Present();
instance.ProcessEvents();
}
#endif
}
Emscripten ile uygulamayı oluşturma
Uygulamayı Emscripten ile oluşturmak için tek değişiklik olarak cmake
komutlarının başına sihirli emcmake
kabuk komut dosyasını eklemeniz gerekir. Bu kez uygulamayı bir build-web
alt klasöründe oluşturun ve bir HTTP sunucusu başlatın. Son olarak, tarayıcınızı açıp build-web/app.html
adresini ziyaret edin.
# Build the app with Emscripten.
$ emcmake cmake -B build-web && cmake --build build-web
# Start a HTTP server.
$ npx http-server

Sırada ne var?
Gelecekte göreceğiniz değişiklikler:
- webgpu.h ve webgpu_cpp.h API'lerinin kararlılığında iyileştirmeler yapıldı.
- Android ve iOS için ilk Dawn desteği.
Bu süre zarfında lütfen öneri ve sorularınızla birlikte Emscripten için WebGPU sorunları ve Dawn sorunları bildirin.
Kaynaklar
Bu uygulamanın kaynak kodunu inceleyebilirsiniz.
WebGPU ile C++'ta sıfırdan yerel 3D uygulamalar oluşturma hakkında daha fazla bilgi edinmek istiyorsanız Learn WebGPU for C++ documentation (C++ için WebGPU'yu Öğrenme) ve Dawn Native WebGPU Examples (Dawn Yerel WebGPU Örnekleri) başlıklı makaleleri inceleyin.
Rust ile ilgileniyorsanız WebGPU'ya dayalı wgpu grafik kitaplığını da inceleyebilirsiniz. hello-triangle demosuna göz atın.
Teşekkür
Bu makale Corentin Wallez, Kai Ninomiya ve Rachel Andrew tarafından incelenmiştir.
Marc-Olivier Jodoin'in Unsplash'teki fotoğrafı.