वेब डेवलपर के लिए, WebGPU एक वेब ग्राफ़िक्स एपीआई है. यह जीपीयू को एक साथ और तेज़ी से ऐक्सेस करने की सुविधा देता है. WebGPU, आधुनिक हार्डवेयर की सुविधाओं को दिखाता है. साथ ही, Direct3D 12, Metal, और Vulkan की तरह ही GPU पर रेंडरिंग और कंप्यूटेशन ऑपरेशन की अनुमति देता है.
यह सच है, लेकिन यह स्टोरी अधूरी है. WebGPU, कई कंपनियों के साथ मिलकर किए गए काम का नतीजा है. इनमें Apple, Google, Intel, Mozilla, और Microsoft जैसी बड़ी कंपनियां शामिल हैं. इनमें से कुछ लोगों को पता चला कि WebGPU, JavaScript API से ज़्यादा हो सकता है. यह वेब के अलावा, सभी पारिस्थितिक तंत्र के डेवलपर के लिए, क्रॉस-प्लैटफ़ॉर्म ग्राफ़िक्स एपीआई हो सकता है.
मुख्य इस्तेमाल के उदाहरण को पूरा करने के लिए, Chrome 113 में JavaScript API को पेश किया गया था. हालांकि, इसके साथ ही एक और अहम प्रोजेक्ट भी डेवलप किया गया है: webgpu.h C API. इस C हेडर फ़ाइल में, WebGPU के सभी उपलब्ध प्रोसेस और डेटा स्ट्रक्चर की सूची दी गई है. यह प्लैटफ़ॉर्म-एग्नोस्टिक हार्डवेयर ऐब्स्ट्रैक्ट लेयर की तरह काम करता है. इसकी मदद से, अलग-अलग प्लैटफ़ॉर्म पर एक जैसा इंटरफ़ेस देकर, अलग-अलग प्लैटफ़ॉर्म के हिसाब से ऐप्लिकेशन बनाए जा सकते हैं.
इस दस्तावेज़ में, WebGPU का इस्तेमाल करके छोटे C++ ऐप्लिकेशन लिखने का तरीका बताया गया है. यह वेब और खास प्लैटफ़ॉर्म, दोनों पर चलता है. स्पॉइलर अलर्ट: आपको वही लाल त्रिभुज दिखेगा जो ब्राउज़र विंडो और डेस्कटॉप विंडो में दिखता है. इसके लिए, आपको अपने कोडबेस में ज़्यादा बदलाव करने की ज़रूरत नहीं होगी.
यह कैसे काम करता है?
पूरा किया गया ऐप्लिकेशन देखने के लिए, WebGPU क्रॉस-प्लैटफ़ॉर्म ऐप्लिकेशन का डेटा स्टोर करने की जगह देखें.
यह ऐप्लिकेशन, C++ का एक छोटा सा उदाहरण है. इसमें एक ही कोडबेस से डेस्कटॉप और वेब ऐप्लिकेशन बनाने के लिए, WebGPU का इस्तेमाल करने का तरीका बताया गया है. यह webgpu_cpp.h नाम के C++ रैपर के ज़रिए, प्लैटफ़ॉर्म के हिसाब से हार्डवेयर एब्स्ट्रैक्शन लेयर के तौर पर, WebGPU के webgpu.h का इस्तेमाल करता है.
वेब पर, ऐप्लिकेशन को Emscripten के लिए बनाया गया है. इसमें JavaScript API के ऊपर webgpu.h को लागू करने वाली बाइंडिंग हैं. macOS या Windows जैसे खास प्लैटफ़ॉर्म पर, इस प्रोजेक्ट को Dawn के लिए बनाया जा सकता है. यह Chromium का क्रॉस-प्लैटफ़ॉर्म WebGPU लागू करने वाला टूल है. यह बताना ज़रूरी है कि wgpu-native भी मौजूद है. यह webgpu.h का Rust वर्शन है. हालांकि, इस दस्तावेज़ में इसका इस्तेमाल नहीं किया गया है.
अपनी प्रोफ़ाइल बनाना शुरू करें
शुरू करने के लिए, आपको C++ कंपाइलर और CMake की ज़रूरत होगी, ताकि अलग-अलग प्लैटफ़ॉर्म के लिए बने बिल्ड को स्टैंडर्ड तरीके से मैनेज किया जा सके. खास तौर पर बनाए गए फ़ोल्डर में, main.cpp
सोर्स फ़ाइल और CMakeLists.txt
बिल्ड फ़ाइल बनाएं.
फ़िलहाल, main.cpp
फ़ाइल में खाली main()
फ़ंक्शन होना चाहिए.
int main() {}
CMakeLists.txt
फ़ाइल में प्रोजेक्ट के बारे में बुनियादी जानकारी होती है. आखिरी लाइन से पता चलता है कि इस फ़ाइल का नाम "app" है और इसका सोर्स कोड main.cpp
है.
cmake_minimum_required(VERSION 3.13) # CMake version check
project(app) # Create project "app"
set(CMAKE_CXX_STANDARD 20) # Enable C++20 standard
add_executable(app "main.cpp")
"build/" सब-फ़ोल्डर में बिल्ड फ़ाइलें बनाने के लिए, cmake -B build
चलाएं. साथ ही, ऐप्लिकेशन को बिल्ड करने और उसे चलाने लायक फ़ाइल जनरेट करने के लिए, cmake --build build
चलाएं.
# Build the app with CMake.
$ cmake -B build && cmake --build build
# Run the app.
$ ./build/app
ऐप्लिकेशन चलता है, लेकिन अभी तक कोई आउटपुट नहीं मिला है, क्योंकि आपको स्क्रीन पर चीज़ों को ड्रॉ करने के तरीके की ज़रूरत है.
सुबह की शुरुआत करें
त्रिकोण बनाने के लिए, Dawn का इस्तेमाल किया जा सकता है. यह Chromium का क्रॉस-प्लैटफ़ॉर्म WebGPU लागू करने वाला टूल है. इसमें स्क्रीन पर ड्रॉ करने के लिए, GLFW C++ लाइब्रेरी शामिल है. Dawn को डाउनलोड करने का एक तरीका यह है कि आप इसे अपनी रिपॉज़िटरी में git सबमोड्यूल के तौर पर जोड़ें. नीचे दिए गए निर्देश, इसे "dawn/" सब-फ़ोल्डर में फ़ेच करते हैं.
$ git init
$ git submodule add https://dawn.googlesource.com/dawn
इसके बाद, CMakeLists.txt
फ़ाइल में इस तरह से जोड़ें:
- CMake
DAWN_FETCH_DEPENDENCIES
विकल्प, Dawn की सभी डिपेंडेंसी फ़ेच करता है. dawn/
सब-फ़ोल्डर को टारगेट में शामिल किया गया है.- आपका ऐप्लिकेशन,
dawn::webgpu_dawn
,glfw
, औरwebgpu_glfw
टारगेट पर निर्भर करेगा, ताकि आप बाद मेंmain.cpp
फ़ाइल में उनका इस्तेमाल कर सकें.
…
set(DAWN_FETCH_DEPENDENCIES ON)
add_subdirectory("dawn" EXCLUDE_FROM_ALL)
target_link_libraries(app PRIVATE dawn::webgpu_dawn glfw webgpu_glfw)
विंडो खोलना
डॉन अब उपलब्ध है, इसलिए स्क्रीन पर चीज़ें ड्रॉ करने के लिए GLFW का इस्तेमाल करें. webgpu_glfw
में शामिल इस लाइब्रेरी की मदद से, विंडो मैनेजमेंट के लिए ऐसा कोड लिखा जा सकता है जो किसी भी प्लैटफ़ॉर्म पर काम करता हो.
512x512 के रिज़ॉल्यूशन वाली "WebGPU विंडो" नाम की विंडो खोलने के लिए, main.cpp
फ़ाइल को यहां दिए गए तरीके से अपडेट करें. ध्यान दें कि यहां glfwWindowHint()
का इस्तेमाल, किसी खास ग्राफ़िक्स एपीआई को शुरू करने का अनुरोध करने के लिए नहीं किया गया है.
#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();
}
ऐप्लिकेशन को फिर से बनाकर, पहले की तरह चलाने पर अब एक खाली विंडो दिखती है. आपकी प्रोग्रेस दिख रही है!
जीपीयू डिवाइस पाना
JavaScript में, जीपीयू को ऐक्सेस करने के लिए navigator.gpu
आपका एंट्री पॉइंट होता है. C++ में, आपको मैन्युअल रूप से एक wgpu::Instance
वैरिएबल बनाना होगा, जिसका इस्तेमाल उसी मकसद के लिए किया जाता है. आसानी के लिए, main.cpp
फ़ाइल में सबसे ऊपर instance
का एलान करें और main()
में wgpu::CreateInstance()
को कॉल करें.
…
#include <webgpu/webgpu_cpp.h>
wgpu::Instance instance;
…
int main() {
instance = wgpu::CreateInstance();
Start();
}
JavaScript API के स्ट्रक्चर की वजह से, जीपीयू को असाइनॉन्स तरीके से ऐक्सेस किया जाता है. C++ में, GetAdapter()
और GetDevice()
नाम के दो हेल्पर फ़ंक्शन बनाएं. ये wgpu::Adapter
और wgpu::Device
के साथ कॉलबैक फ़ंक्शन दिखाते हैं.
#include <iostream>
…
void GetAdapter(void (*callback)(wgpu::Adapter)) {
instance.RequestAdapter(
nullptr,
[](WGPURequestAdapterStatus status, WGPUAdapter cAdapter,
const char* message, void* userdata) {
if (status != WGPURequestAdapterStatus_Success) {
exit(0);
}
wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
reinterpret_cast<void (*)(wgpu::Adapter)>(userdata)(adapter);
}, reinterpret_cast<void*>(callback));
}
void GetDevice(void (*callback)(wgpu::Device)) {
adapter.RequestDevice(
nullptr,
[](WGPURequestDeviceStatus status, WGPUDevice cDevice,
const char* message, void* userdata) {
wgpu::Device device = wgpu::Device::Acquire(cDevice);
device.SetUncapturedErrorCallback(
[](WGPUErrorType type, const char* message, void* userdata) {
std::cout << "Error: " << type << " - message: " << message;
},
nullptr);
reinterpret_cast<void (*)(wgpu::Device)>(userdata)(device);
}, reinterpret_cast<void*>(callback));
}
आसानी से ऐक्सेस करने के लिए, main.cpp
फ़ाइल में सबसे ऊपर दो वैरिएबल wgpu::Adapter
और wgpu::Device
डालें. GetAdapter()
को कॉल करने के लिए, main()
फ़ंक्शन को अपडेट करें और उसके नतीजे के कॉलबैक को adapter
को असाइन करें. इसके बाद, Start()
को कॉल करने से पहले, GetDevice()
को कॉल करें और उसके नतीजे के कॉलबैक को device
को असाइन करें.
wgpu::Adapter adapter;
wgpu::Device device;
…
int main() {
instance = wgpu::CreateInstance();
GetAdapter([](wgpu::Adapter a) {
adapter = a;
GetDevice([](wgpu::Device d) {
device = d;
Start();
});
});
}
त्रिकोण बनाना
स्वैप चेन को JavaScript API में नहीं दिखाया जाता, क्योंकि ब्राउज़र इसका ध्यान रखता है. C++ में, आपको इसे मैन्युअल तरीके से बनाना होगा. एक बार फिर से, सुविधा के लिए, main.cpp
फ़ाइल के सबसे ऊपर wgpu::Surface
वैरिएबल का एलान करें. Start()
में GLFW विंडो बनाने के तुरंत बाद, wgpu::glfw::CreateSurfaceForWindow()
फ़ंक्शन को कॉल करके wgpu::Surface
बनाएं. यह एचटीएमएल कैनवस की तरह ही होता है. इसके बाद, InitGraphics()
में नए हेल्पर ConfigureSurface()
फ़ंक्शन को कॉल करके, इसे कॉन्फ़िगर करें. while लूप में अगला टेक्सचर दिखाने के लिए, आपको surface.Present()
को भी कॉल करना होगा. इसका कोई असर नहीं पड़ता, क्योंकि अभी तक रेंडरिंग नहीं हो रही है.
#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};
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();
}
}
अब नीचे दिए गए कोड के साथ रेंडर पाइपलाइन बनाने का सही समय है. आसानी से ऐक्सेस करने के लिए, main.cpp
फ़ाइल में सबसे ऊपर wgpu::RenderPipeline
वैरिएबल का एलान करें और InitGraphics()
में हेल्पर फ़ंक्शन CreateRenderPipeline()
को कॉल करें.
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::ShaderModuleWGSLDescriptor wgslDesc{};
wgslDesc.code = shaderCode;
wgpu::ShaderModuleDescriptor shaderModuleDescriptor{
.nextInChain = &wgslDesc};
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();
}
आखिर में, हर फ़्रेम के नाम वाले Render()
फ़ंक्शन में, GPU को रेंडरिंग के निर्देश भेजें.
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);
}
CMake की मदद से ऐप्लिकेशन को फिर से बनाकर उसे चलाने पर, अब हमें विंडो में लाल रंग का वह त्रिकोण दिख रहा है जिसका हम इंतज़ार कर रहे थे! ब्रेक लें—आपको इसकी ज़रूरत है.
WebAssembly में कंपाइल करें
आइए, अब उन कम से कम बदलावों पर नज़र डालते हैं, जो इस लाल त्रिभुज को किसी ब्राउज़र विंडो में बनाने के लिए आपके मौजूदा कोड बेस को अडजस्ट करने के लिए ज़रूरी हैं. फिर से, ऐप्लिकेशन को Emscripten के लिए बनाया गया है. यह C/C++ प्रोग्राम को WebAssembly में कंपाइल करने के लिए इस्तेमाल किया जाने वाला टूल है. इसमें JavaScript API के ऊपर webgpu.h को लागू करने वाली बाइंडिंग होती हैं.
CMake की सेटिंग अपडेट करना
Emscripten इंस्टॉल होने के बाद, CMakeLists.txt
की बिल्ड फ़ाइल को नीचे बताए गए तरीके से अपडेट करें.
आपको सिर्फ़ हाइलाइट किए गए कोड में बदलाव करना होगा.
set_target_properties
का इस्तेमाल, टारगेट फ़ाइल में "html" फ़ाइल एक्सटेंशन को अपने-आप जोड़ने के लिए किया जाता है. दूसरे शब्दों में, आपको "app.html" फ़ाइल जनरेट होगी.- Emscripten में WebGPU की सुविधा चालू करने के लिए,
USE_WEBGPU
ऐप्लिकेशन लिंक का विकल्प ज़रूरी है. इसके बिना, आपकीmain.cpp
फ़ाइलwebgpu/webgpu_cpp.h
फ़ाइल को ऐक्सेस नहीं कर सकती. - यहां
USE_GLFW
ऐप्लिकेशन लिंक विकल्प भी ज़रूरी है, ताकि आप अपने जीएलएफ़डब्ल्यू कोड का फिर से इस्तेमाल कर सकें.
cmake_minimum_required(VERSION 3.13) # CMake version check
project(app) # Create project "app"
set(CMAKE_CXX_STANDARD 20) # Enable C++20 standard
add_executable(app "main.cpp")
if(EMSCRIPTEN)
set_target_properties(app PROPERTIES SUFFIX ".html")
target_link_options(app PRIVATE "-sUSE_WEBGPU=1" "-sUSE_GLFW=3")
else()
set(DAWN_FETCH_DEPENDENCIES ON)
add_subdirectory("dawn" EXCLUDE_FROM_ALL)
target_link_libraries(app PRIVATE dawn::webgpu_dawn glfw webgpu_glfw)
endif()
कोड अपडेट करना
Emscripten में, wgpu::surface
बनाने के लिए एचटीएमएल कैनवस एलिमेंट की ज़रूरत होती है. इसके लिए, instance.CreateSurface()
को कॉल करें और Emscripten से जनरेट किए गए एचटीएमएल पेज में सही एचटीएमएल कैनवस एलिमेंट से मैच करने के लिए, #canvas
सिलेक्टर तय करें.
while लूप का इस्तेमाल करने के बजाय, emscripten_set_main_loop(Render)
को कॉल करें. इससे यह पक्का किया जा सकता है कि Render()
फ़ंक्शन को सही दर से कॉल किया जाए, ताकि वह ब्राउज़र और मॉनिटर के साथ सही तरीके से अलाइन हो सके.
#include <GLFW/glfw3.h>
#include <webgpu/webgpu_cpp.h>
#include <iostream>
#if defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#else
#include <webgpu/webgpu_glfw.h>
#endif
void Start() {
if (!glfwInit()) {
return;
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window =
glfwCreateWindow(kWidth, kHeight, "WebGPU window", nullptr, nullptr);
#if defined(__EMSCRIPTEN__)
wgpu::SurfaceDescriptorFromCanvasHTMLSelector canvasDesc{};
canvasDesc.selector = "#canvas";
wgpu::SurfaceDescriptor surfaceDesc{.nextInChain = &canvasDesc};
surface = instance.CreateSurface(&surfaceDesc);
#else
surface = wgpu::glfw::CreateSurfaceForWindow(instance, window);
#endif
InitGraphics();
#if defined(__EMSCRIPTEN__)
emscripten_set_main_loop(Render, 0, false);
#else
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
Render();
surface.Present();
instance.ProcessEvents();
}
#endif
}
Emscripten की मदद से ऐप्लिकेशन बनाना
Emscripten की मदद से ऐप्लिकेशन बनाने के लिए, cmake
कमांड के आगे जादुई emcmake
शेल स्क्रिप्ट जोड़ना ज़रूरी है. इस बार, build-web
सब-फ़ोल्डर में ऐप्लिकेशन जनरेट करें और एचटीटीपी सर्वर शुरू करें. आखिर में, अपना ब्राउज़र खोलें और build-web/app.html
पर जाएं.
# Build the app with Emscripten.
$ emcmake cmake -B build-web && cmake --build build-web
# Start a HTTP server.
$ npx http-server
आगे क्या करना है
आने वाले समय में, ये बदलाव हो सकते हैं:
- webgpu.h और webgpu_cpp.h API के स्टेबल होने से जुड़े सुधार.
- Android और iOS के लिए डॉन शुरुआती सहायता.
इस बीच, कृपया Emscripten के लिए WebGPU से जुड़ी समस्याओं और Dawn से जुड़ी समस्याओं के बारे में सुझाव और सवाल सबमिट करें.
संसाधन
इस ऐप्लिकेशन का सोर्स कोड देखें.
अगर आपको WebGPU की मदद से, C++ में शुरू से ही नेटिव 3D ऐप्लिकेशन बनाने के बारे में ज़्यादा जानना है, तो C++ दस्तावेज़ के लिए WebGPU के बारे में जानें और Dawn Native WebGPU के उदाहरण देखें.
अगर आपकी दिलचस्पी Rust में है, तो WebGPU पर आधारित wgpu ग्राफ़िक लाइब्रेरी को भी एक्सप्लोर किया जा सकता है. hello-triangle का डेमो देखें.
लोगों का आभार
इस लेख की समीक्षा कॉर्नेटिन वॉलेस, काई निनोमिया, और रेचेल एंड्रयू ने की है.
Unsplash पर Marc-Olivier Jodoin की फ़ोटो.