WebGPU দিয়ে একটি অ্যাপ তৈরি করুন

ফ্রাঁসোয়া বিউফোর্ট
François Beaufort

প্রকাশিত: ২০ জুলাই, ২০২৩, সর্বশেষ আপডেট: ২২ অক্টোবর, ২০২৫

ওয়েব ডেভেলপারদের জন্য, WebGPU হল একটি ওয়েব গ্রাফিক্স API যা GPU গুলিতে একীভূত এবং দ্রুত অ্যাক্সেস প্রদান করে। WebGPU আধুনিক হার্ডওয়্যার ক্ষমতা প্রকাশ করে এবং Direct3D 12, Metal এবং Vulkan এর মতো GPU তে রেন্ডারিং এবং গণনা অপারেশনের অনুমতি দেয়।

যদিও সত্য, গল্পটি অসম্পূর্ণ। WebGPU হল অ্যাপল, গুগল, ইন্টেল, মজিলা এবং মাইক্রোসফ্টের মতো বড় কোম্পানিগুলির একটি যৌথ প্রচেষ্টার ফলাফল। তাদের মধ্যে, কেউ কেউ বুঝতে পেরেছিলেন যে WebGPU কেবল একটি জাভাস্ক্রিপ্ট API-এর চেয়েও বেশি কিছু হতে পারে, বরং ওয়েব ছাড়াও ইকোসিস্টেম জুড়ে ডেভেলপারদের জন্য একটি ক্রস-প্ল্যাটফর্ম গ্রাফিক্স API হতে পারে।

প্রাথমিক ব্যবহারের ক্ষেত্রে, Chrome 113-এ একটি JavaScript API চালু করা হয়েছিল। তবে, এর পাশাপাশি আরেকটি গুরুত্বপূর্ণ প্রকল্প তৈরি করা হয়েছে: webgpu.h C API। এই C হেডার ফাইলটি WebGPU-এর সমস্ত উপলব্ধ পদ্ধতি এবং ডেটা স্ট্রাকচার তালিকাভুক্ত করে। এটি একটি প্ল্যাটফর্ম-অ্যাগনস্টিক হার্ডওয়্যার অ্যাবস্ট্রাকশন স্তর হিসেবে কাজ করে, যা আপনাকে বিভিন্ন প্ল্যাটফর্ম জুড়ে একটি সামঞ্জস্যপূর্ণ ইন্টারফেস প্রদান করে প্ল্যাটফর্ম-নির্দিষ্ট অ্যাপ্লিকেশন তৈরি করতে দেয়।

এই ডকুমেন্টে, আপনি শিখবেন কিভাবে WebGPU ব্যবহার করে একটি ছোট C++ অ্যাপ লিখতে হয় যা ওয়েব এবং নির্দিষ্ট প্ল্যাটফর্ম উভয় ক্ষেত্রেই চলে। স্পয়লার সতর্কতা, আপনি একই লাল ত্রিভুজ পাবেন যা ব্রাউজার উইন্ডো এবং ডেস্কটপ উইন্ডোতে প্রদর্শিত হয় এবং আপনার কোডবেসে ন্যূনতম সমন্বয় করা হয়।

macOS-এর একটি ব্রাউজার উইন্ডো এবং একটি ডেস্কটপ উইন্ডোতে WebGPU দ্বারা চালিত একটি লাল ত্রিভুজের স্ক্রিনশট।
একটি ব্রাউজার উইন্ডো এবং একটি ডেস্কটপ উইন্ডোতে WebGPU দ্বারা চালিত একই ত্রিভুজ।

এটা কিভাবে কাজ করে?

সম্পূর্ণ অ্যাপ্লিকেশনটি দেখতে WebGPU ক্রস-প্ল্যাটফর্ম অ্যাপ রিপোজিটরিটি দেখুন।

এই অ্যাপটি একটি ন্যূনতম C++ উদাহরণ যা দেখায় কিভাবে WebGPU ব্যবহার করে একটি একক কোডবেস থেকে ডেস্কটপ এবং ওয়েব অ্যাপ তৈরি করতে হয়। এর ভিতরে, এটি WebGPU-এর webgpu.h ব্যবহার করে একটি প্ল্যাটফর্ম-অ্যাগনস্টিক হার্ডওয়্যার অ্যাবস্ট্রাকশন লেয়ার হিসেবে webgpu_cpp.h নামক একটি C++ র‍্যাপারের মাধ্যমে।

ওয়েবে, অ্যাপটি emdawnwebgpu (Emscripten Dawn WebGPU) এর বিপরীতে তৈরি, যার জাভাস্ক্রিপ্ট 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.22) # 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://github.com/google/dawn.git

তারপর, CMakeLists.txt ফাইলে নিম্নরূপে যুক্ত করুন:

  • CMake DAWN_FETCH_DEPENDENCIES বিকল্পটি সমস্ত Dawn নির্ভরতা আনে।
  • dawn/ sub ফোল্ডারটি টার্গেটের মধ্যে অন্তর্ভুক্ত।
  • আপনার অ্যাপটি webgpu_dawn , webgpu_glfw , এবং glfw টার্গেটের উপর নির্ভর করবে যাতে আপনি পরে main.cpp ফাইলে সেগুলি ব্যবহার করতে পারেন।

set(DAWN_FETCH_DEPENDENCIES ON)
add_subdirectory("dawn" EXCLUDE_FROM_ALL)

target_link_libraries(app PRIVATE webgpu_dawn webgpu_glfw glfw)

একটি জানালা খুলুন

এখন যেহেতু ডন উপলব্ধ, স্ক্রিনে জিনিস আঁকতে GLFW ব্যবহার করুন। সুবিধার জন্য webgpu_glfw এ অন্তর্ভুক্ত এই লাইব্রেরিটি আপনাকে উইন্ডো পরিচালনার জন্য প্ল্যাটফর্ম-অ্যাগনস্টিক কোড লিখতে দেয়।

৫১২x৫১২ রেজোলিউশনের "WebGPU window" নামের একটি উইন্ডো খুলতে, নীচের মত main.cpp ফাইলটি আপডেট করুন। মনে রাখবেন যে glfwWindowHint() এখানে কোনও নির্দিষ্ট গ্রাফিক্স API ইনিশিয়ালাইজেশনের অনুরোধ করার জন্য ব্যবহার করা হয়নি।

#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();
}

অ্যাপটি পুনর্নির্মাণ করে আগের মতো চালানোর ফলে একটি খালি উইন্ডো দেখা যাচ্ছে। আপনি উন্নতি করছেন!

একটি খালি macOS উইন্ডোর স্ক্রিনশট।
একটা খালি জানালা।

GPU ডিভাইস পান

জাভাস্ক্রিপ্টে, navigator.gpu হল GPU অ্যাক্সেস করার জন্য আপনার এন্ট্রিপয়েন্ট। C++ তে, আপনাকে ম্যানুয়ালি একটি wgpu::Instance ভেরিয়েবল তৈরি করতে হবে যা একই উদ্দেশ্যে ব্যবহৃত হয়। সুবিধার জন্য, main.cpp ফাইলের উপরে instance ঘোষণা করুন এবং Init() ভিতরে wgpu::CreateInstance() কল করুন।

#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 ফাইলের উপরে দুটি ভেরিয়েবল wgpu::Adapter এবং wgpu::Device ঘোষণা করুন। instance.RequestAdapter() কল করার জন্য Init() ফাংশনটি আপডেট করুন এবং এর ফলাফল কলব্যাক adapter বরাদ্দ করুন তারপর adapter.RequestDevice() কল করুন এবং এর ফলাফল কলব্যাক device এ বরাদ্দ করুন।

#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);
}

একটি ত্রিভুজ আঁকুন।

জাভাস্ক্রিপ্ট API-তে সোয়াপ চেইনটি উন্মুক্ত হয় না কারণ ব্রাউজার এটির যত্ন নেয়। C++-এ, আপনাকে এটি ম্যানুয়ালি তৈরি করতে হবে। আবারও, সুবিধার জন্য, main.cpp ফাইলের উপরে একটি wgpu::Surface ভেরিয়েবল ঘোষণা করুন। Start() এ GLFW উইন্ডো তৈরি করার পর, একটি wgpu wgpu::Surface (HTML ক্যানভাসের মতো) তৈরি করতে সহজ wgpu::glfw::CreateSurfaceForWindow() ফাংশনটি কল করুন এবং 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::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();
}

অবশেষে, প্রতিটি ফ্রেম নামক 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-তে কম্পাইল করুন

এবার দেখা যাক ব্রাউজার উইন্ডোতে এই লাল ত্রিভুজটি আঁকতে আপনার বিদ্যমান কোডবেস সামঞ্জস্য করতে প্রয়োজনীয় ন্যূনতম পরিবর্তনগুলি। আবার, অ্যাপটি emdawnwebgpu (Emscripten Dawn WebGPU) এর উপর ভিত্তি করে তৈরি করা হয়েছে, যার জাভাস্ক্রিপ্ট API এর উপরে webgpu.h বাস্তবায়নের জন্য বাইন্ডিং রয়েছে। এটি WebAssembly-তে C/C++ প্রোগ্রাম কম্পাইল করার জন্য একটি টুল Emscripten ব্যবহার করে।

CMake সেটিংস আপডেট করুন

Emscripten ইনস্টল হয়ে গেলে, CMakeLists.txt বিল্ড ফাইলটি নিম্নরূপ আপডেট করুন। হাইলাইট করা কোডটিই একমাত্র জিনিস যা আপনাকে পরিবর্তন করতে হবে।

  • set_target_properties স্বয়ংক্রিয়ভাবে "html" ফাইল এক্সটেনশনটি টার্গেট ফাইলে যোগ করতে ব্যবহৃত হয়। অন্য কথায়, আপনি একটি "app.html" ফাইল তৈরি করবেন।
  • emdawnwebgpu_cpp টার্গেট লিঙ্ক লাইব্রেরি Emscripten-এ WebGPU সাপোর্ট সক্ষম করে। এটি ছাড়া, আপনার main.cpp ফাইলটি webgpu/webgpu_cpp.h ফাইলটি অ্যাক্সেস করতে পারবে না।
  • ASYNCIFY=1 অ্যাপ লিঙ্ক বিকল্পটি সিঙ্ক্রোনাস C++ কোডকে অ্যাসিনক্রোনাস জাভাস্ক্রিপ্টের সাথে ইন্টারঅ্যাক্ট করতে দেয়।
  • USE_GLFW=3 অ্যাপ লিঙ্ক বিকল্পটি Emscripten কে GLFW 3 API এর অন্তর্নির্মিত জাভাস্ক্রিপ্ট বাস্তবায়ন ব্যবহার করতে বলে।
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)
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()

কোডটি আপডেট করুন

while লুপ ব্যবহার করার পরিবর্তে, emscripten_set_main_loop(Render) কল করুন যাতে নিশ্চিত করা যায় যে Render() ফাংশনটি সঠিক মসৃণ হারে কল করা হচ্ছে এবং ব্রাউজার এবং মনিটরের সাথে সঠিকভাবে লাইন আপ করছে।

#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 দিয়ে অ্যাপটি তৈরি করুন

Emscripten দিয়ে অ্যাপটি তৈরি করার জন্য একমাত্র যে পরিবর্তনটি প্রয়োজন তা হলো cmake কমান্ডগুলিকে ম্যাজিকাল emcmake শেল স্ক্রিপ্টের সাথে যুক্ত করা। এবার, একটি build-web সাব ফোল্ডারে অ্যাপটি তৈরি করুন এবং একটি HTTP সার্ভার শুরু করুন। অবশেষে, আপনার ব্রাউজারটি খুলুন এবং 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
ব্রাউজার উইন্ডোতে একটি লাল ত্রিভুজের স্ক্রিনশট।
ব্রাউজার উইন্ডোতে একটি লাল ত্রিভুজ।

এরপর কি?

সামনের দিকে তাকালে, আপনি অ্যান্ড্রয়েড এবং আইওএস-এ ডনের প্রাথমিক সহায়তা আশা করতে পারেন।

ইতিমধ্যে, Emscripten এবং Dawn এর জন্য WebGPU সমস্যাগুলি পরামর্শ এবং প্রশ্ন সহ ফাইল করুন।

রিসোর্স

এই অ্যাপটির সোর্স কোডটি অন্বেষণ করতে দ্বিধা করবেন না।

আপনি যদি WebGPU ব্যবহার করে C++ তে নেটিভ 3D অ্যাপ্লিকেশন তৈরিতে আরও বেশি আগ্রহী হন, তাহলে C++ ডকুমেন্টেশনের জন্য Learn WebGPU এবং Dawn Native WebGPU Examples দেখুন।

যদি আপনি রাস্ট সম্পর্কে আগ্রহী হন, তাহলে আপনি WebGPU-এর উপর ভিত্তি করে wgpu গ্রাফিক্স লাইব্রেরিটিও ঘুরে দেখতে পারেন। তাদের hello-triangle ডেমোটি একবার দেখুন।

স্বীকৃতি

এই প্রবন্ধটি পর্যালোচনা করেছেন কোরেন্টিন ওয়ালেজ , কাই নিনোমিয়া এবং র‍্যাচেল অ্যান্ড্রু