Jetpack WebGPU का इस्तेमाल करने के लिए, आपके प्रोजेक्ट को ये ज़रूरी शर्तें पूरी करनी होंगी:
- कम से कम एपीआई लेवल: Android का एपीआई लेवल 24 (Nougat) या इसके बाद का वर्शन होना ज़रूरी है.
- हार्डवेयर: बैकएंड के लिए, Vulkan 1.1 या इसके बाद के वर्शन को सपोर्ट करने वाले डिवाइसों का इस्तेमाल करना बेहतर होता है.
- कंपैटिलिटी मोड और OpenGL ES सपोर्ट: कंपैटिलिटी मोड के साथ WebGPU का इस्तेमाल किया जा सकता है. इसके लिए, स्टैंडर्ड
featureLevelविकल्प कोcompatibilityपर सेट करें. ऐसाGPUAdapterका अनुरोध करते समय किया जाता है.
// Example of requesting an adapter with "compatibility" mode enabled:
val adapter = instance.requestAdapter(
GPURequestAdapterOptions(featureLevel = FeatureLevel.Compatibility))
इंस्टॉलेशन और सेटअप
ज़रूरी शर्तें:
Android Studio: आधिकारिक वेबसाइट से Android Studio का नया वर्शन डाउनलोड करें. इसके बाद, Android Studio इंस्टॉलेशन गाइड में दिए गए निर्देशों का पालन करें.
नया प्रोजेक्ट बनाएं
Android Studio इंस्टॉल हो जाने के बाद, WebGPU प्रोजेक्ट सेट अप करने के लिए यह तरीका अपनाएं:
- नया प्रोजेक्ट शुरू करना: Android Studio खोलें और नया प्रोजेक्ट पर क्लिक करें.
कोई टेंप्लेट चुनें: Android Studio में बिना ऐक्टिविटी वाला टेंप्लेट चुनें और आगे बढ़ें पर क्लिक करें.
पहली इमेज.Android Studio में नया प्रोजेक्ट बनाना अपने प्रोजेक्ट को कॉन्फ़िगर करें:
- नाम: अपने प्रोजेक्ट को कोई नाम दें (जैसे, "JetpackWebGPUSample").
- पैकेज का नाम: पुष्टि करें कि पैकेज का नाम, आपके चुने गए नेमस्पेस (जैसे, com.example.webgpuapp) से मेल खाता हो.
- भाषा: Kotlin को चुनें.
- कम से कम लेवल वाला SDK टूल: इस लाइब्रेरी के लिए सुझाए गए API 24: Android 7.0 (Nougat) या इसके बाद के वर्शन को चुनें.
- बिल्ड कॉन्फ़िगरेशन की भाषा: आधुनिक डिपेंडेंसी मैनेजमेंट के लिए, Kotlin DSL (build.gradle.kts) का इस्तेमाल करने का सुझाव दिया जाता है.
दूसरी इमेज.खाली गतिविधि से शुरू करना खत्म करें: खत्म करें पर क्लिक करें और Android Studio के प्रोजेक्ट फ़ाइलों को सिंक करने का इंतज़ार करें.
WebGPU Jetpack लाइब्रेरी जोड़ना
googleकोsettings.gradleमें जोड़ें. इसके लिए, अपने ऐप्लिकेशन में Jetpack लाइब्रेरी का इस्तेमाल करना लेख पढ़ें- अपने ऐप्लिकेशन या मॉड्यूल के लिए, build.gradle फ़ाइल में उन आर्टफ़ैक्ट की डिपेंडेंसी जोड़ें जिनकी आपको ज़रूरत है:
- ध्यान दें: लाइब्रेरी के सबसे नए वर्शन के लिए, webgpu | Jetpack | Android Developers देखें
androidx.webgpu लाइब्रेरी में WebGPU NDK की .so लाइब्रेरी फ़ाइलों के साथ-साथ मैनेज किए गए कोड इंटरफ़ेस भी शामिल होते हैं.
build.gradle फ़ाइल को अपडेट करके, लाइब्रेरी का वर्शन अपडेट किया जा सकता है. इसके बाद, Android Studio में "प्रोजेक्ट सिंक करें" बटन का इस्तेमाल करके, अपने प्रोजेक्ट को Gradle फ़ाइलों के साथ सिंक करें.
हाई-लेवल आर्किटेक्चर
Android ऐप्लिकेशन में WebGPU रेंडरिंग, एक खास रेंडरिंग थ्रेड पर चलती है, ताकि यूज़र इंटरफ़ेस (यूआई) को रिस्पॉन्सिव रखा जा सके.
- यूज़र इंटरफ़ेस (यूआई) लेयर: यूज़र इंटरफ़ेस (यूआई) को Jetpack Compose की मदद से बनाया जाता है. WebGPU की मदद से ड्रॉ की गई सतह को Compose के क्रम में इंटिग्रेट किया जाता है. इसके लिए,
AndroidExternalSurfaceका इस्तेमाल किया जाता है. - रेंडरिंग लॉजिक: यह एक खास क्लास होती है. जैसे, WebGpuRenderer) सभी WebGPU ऑब्जेक्ट को मैनेज करने और रेंडरिंग लूप को कोऑर्डिनेट करने के लिए ज़िम्मेदार होता है.
- शेडर लेयर: res या स्ट्रिंग कॉन्स्टेंट में सेव किया गया WGSL शेडर कोड.
चरण-दर-चरण: सैंपल ऐप्लिकेशन
इस सेक्शन में, स्क्रीन पर रंगीन त्रिकोण रेंडर करने के लिए ज़रूरी चरणों के बारे में बताया गया है. इससे WebGPU के मुख्य वर्कफ़्लो के बारे में पता चलता है.
मुख्य गतिविधि
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WebGpuSurface()
}
}
}
ExternalSurface कंपोज़ेबल
WebgpuSurface.kt नाम की एक नई फ़ाइल बनाएं. यह कंपोज़ेबल, AndroidExternalSurface को रैप करता है, ताकि Compose और आपके रेंडरर के बीच एक ब्रिज बनाया जा सके.
@Composable
fun WebGpuSurface(modifier: Modifier = Modifier) {
// Create and remember a WebGpuRenderer instance.
val renderer = remember { WebGpuRenderer() }
AndroidExternalSurface(
modifier = modifier.fillMaxSize(),
) {
// This block is called when the surface is created or resized.
onSurface { surface, width, height ->
// Run the rendering logic on a background thread.
withContext(Dispatchers.Default) {
try {
// Initialize the renderer with the surface
renderer.init(surface, width, height)
// Render a frame.
renderer.render()
} finally {
// Clean up resources when the surface is destroyed.
renderer.cleanup()
}
}
}
}
}
रेंडरर सेट अप करना
WebGpuRenderer.kt में WebGpuRenderer क्लास बनाएं. यह क्लास, जीपीयू के साथ कम्यूनिकेट करने का काम करेगी.
सबसे पहले, क्लास स्ट्रक्चर और वैरिएबल तय करें:
class WebGpuRenderer() {
private lateinit var webGpu: WebGpu
private lateinit var renderPipeline: GPURenderPipeline
}
सहमति की प्रोसेस चालू करना: इसके बाद, WebGPU इंस्टेंस बनाने और सर्फ़ेस को कॉन्फ़िगर करने के लिए, init फ़ंक्शन लागू करें. इस फ़ंक्शन को, हमने पहले जो बाहरी प्लैटफ़ॉर्म कंपोज़ेबल बनाया था उसके अंदर मौजूद AndroidExternalSurface स्कोप से कॉल किया जाता है.
ध्यान दें: init फ़ंक्शन, सेटअप को आसान बनाने के लिए createWebGpu का इस्तेमाल करता है. यह एक हेल्पर मेथड है, जो androidx.webgpu.helper का हिस्सा है. यह यूटिलिटी, WebGPU इंस्टेंस बनाती है, अडैप्टर चुनती है, और डिवाइस का अनुरोध करती है.
// Inside WebGpuRenderer class
suspend fun init(surface: Surface, width: Int, height: Int) {
// 1. Create Instance & Device
webGpu = createWebGpu(surface)
val device = webGpu.device
// 2. Setup Pipeline (compile shaders)
initPipeline(device)
// 3. Configure the Surface
webGpu.webgpuSurface.configure(
GPUSurfaceConfiguration(
device,
width,
height,
TextureFormat.RGBA8Unorm,
)
)
}
androidx.webgpu लाइब्रेरी में JNI और .so फ़ाइलें शामिल हैं. इन्हें बिल्ड सिस्टम अपने-आप लिंक और मैनेज करता है. सहायता करने वाला यह तरीका
createWebGpu, बंडल किए गए libwebgpu_c_bundled.so को लोड करने का काम करता है.
पाइपलाइन सेटअप करना
अब हमारे पास एक डिवाइस है. हमें GPU को यह बताना होगा कि हमारे ट्राएंगल को कैसे ड्रॉ करना है. इसके लिए, हम एक "पाइपलाइन" बनाते हैं. इसमें हमारा शेडर कोड (WGSL में लिखा गया) शामिल होता है.
शेडर कंपाइल करने और रेंडर पाइपलाइन बनाने के लिए, इस प्राइवेट हेल्पर फ़ंक्शन को अपनी WebGpuRenderer क्लास में जोड़ें.
// Inside WebGpuRenderer class
private fun initPipeline(device: GPUDevice) {
val shaderCode = """
@vertex fn vs_main(@builtin(vertex_index) vertexIndex : u32) ->
@builtin(position) vec4f {
const pos = array(vec2f(0.0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
return vec4f(pos[vertexIndex], 0, 1);
}
@fragment fn fs_main() -> @location(0) vec4f {
return vec4f(1, 0, 0, 1);
}
"""
// Create Shader Module
val shaderModule = device.createShaderModule(
GPUShaderModuleDescriptor(shaderSourceWGSL = GPUShaderSourceWGSL(shaderCode))
)
// Create Render Pipeline
renderPipeline = device.createRenderPipeline(
GPURenderPipelineDescriptor(
vertex = GPUVertexState(
shaderModule,
), fragment = GPUFragmentState(
shaderModule, targets = arrayOf(GPUColorTargetState(TextureFormat.RGBA8Unorm))
), primitive = GPUPrimitiveState(PrimitiveTopology.TriangleList)
)
)
}
फ़्रेम बनाना
पाइपलाइन तैयार होने के बाद, अब हम रेंडर फ़ंक्शन को लागू कर सकते हैं. यह फ़ंक्शन, स्क्रीन से अगली उपलब्ध टेक्सचर हासिल करता है, ड्रॉइंग कमांड रिकॉर्ड करता है, और उन्हें जीपीयू को सबमिट करता है.
इस तरीके को अपनी WebGpuRenderer क्लास में जोड़ें:
// Inside WebGpuRenderer class
fun render() {
if (!::webGpu.isInitialized) {
return
}
val gpu = webGpu
// 1. Get the next available texture from the screen
val surfaceTexture = gpu.webgpuSurface.getCurrentTexture()
// 2. Create a command encoder
val commandEncoder = gpu.device.createCommandEncoder()
// 3. Begin a render pass (clearing the screen to blue)
val renderPass = commandEncoder.beginRenderPass(
GPURenderPassDescriptor(
colorAttachments = arrayOf(
GPURenderPassColorAttachment(
GPUColor(0.0, 0.0, 0.5, 1.0),
surfaceTexture.texture.createView(),
loadOp = LoadOp.Clear,
storeOp = StoreOp.Store,
)
)
)
)
// 4. Draw
renderPass.setPipeline(renderPipeline)
renderPass.draw(3) // Draw 3 vertices
renderPass.end()
// 5. Submit and Present
gpu.device.queue.submit(arrayOf(commandEncoder.finish()))
gpu.webgpuSurface.present()
}
संसाधन हटाना
क्लीनअप फ़ंक्शन लागू करें. जब सर्फ़ेस खत्म हो जाता है, तब WebGpuSurface इस फ़ंक्शन को कॉल करता है.
// Inside WebGpuRenderer class
fun cleanup() {
if (::webGpu.isInitialized) {
webGpu.close()
}
}
रेंडर किया गया आउटपुट
सैंपल ऐप्लिकेशन का स्ट्रक्चर
रेंडरिंग को लागू करने के तरीके को यूज़र इंटरफ़ेस (यूआई) लॉजिक से अलग रखना एक अच्छा तरीका है. जैसे, सैंपल ऐप्लिकेशन में इस्तेमाल किया गया स्ट्रक्चर:
app/src/main/
├── java/com/example/app/
│ ├── MainActivity.kt // Entry point
│ ├── WebGpuSurface.kt // Composable Surface
│ └── WebGpuRenderer.kt // Pure WebGPU logic
- MainActivity.kt: यह ऐप्लिकेशन का एंट्री पॉइंट है. यह कॉन्टेंट को
WebGpuSurfaceकंपोज़ेबल पर सेट करता है. - WebGpuSurface.kt: इसमें
[AndroidExternalSurface](/reference/kotlin/androidx/compose/foundation/package-summary#AndroidExternalSurface(androidx.compose.ui.Modifier,kotlin.Boolean,androidx.compose.ui.unit.IntSize,androidx.compose.foundation.AndroidExternalSurfaceZOrder,kotlin.Boolean,kotlin.Function1))का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को तय किया जाता है. यहSurfaceके लाइफ़साइकल स्कोप को मैनेज करता है. साथ ही, यह सर्फ़ेस तैयार होने पर रेंडरर को शुरू करता है और सर्फ़ेस के बंद होने पर उसे बंद करता है. - WebGpuRenderer.kt: इसमें WebGPU से जुड़े सभी लॉजिक शामिल होते हैं. जैसे, डिवाइस बनाना, पाइपलाइन सेटअप करना. यह यूज़र इंटरफ़ेस (यूआई) से अलग होता है. इसे सिर्फ़
[Surface](/reference/android/view/Surface.html)और डाइमेंशन मिलते हैं, ताकि यह उन्हें दिखा सके.
लाइफ़साइकल और संसाधन मैनेजमेंट
लाइफ़साइकल मैनेजमेंट को Jetpack Compose में [AndroidExternalSurface](/reference/kotlin/androidx/compose/foundation/package-summary#AndroidExternalSurface(androidx.compose.ui.Modifier,kotlin.Boolean,androidx.compose.ui.unit.IntSize,androidx.compose.foundation.AndroidExternalSurfaceZOrder,kotlin.Boolean,kotlin.Function1)) की ओर से उपलब्ध कराए गए Kotlin Coroutine स्कोप से मैनेज किया जाता है.
- सरफ़ेस बनाना:
onSurfaceलैंबडा ब्लॉक की शुरुआत में,DeviceऔरSurfaceकॉन्फ़िगरेशन को शुरू करें.Surfaceके उपलब्ध होते ही यह कोड तुरंत काम करने लगता है. - सरफ़ेस डिस्ट्रक्शन: जब उपयोगकर्ता किसी दूसरे पेज पर जाता है या सिस्टम
Surfaceको बंद कर देता है, तब लैंबडा ब्लॉक रद्द हो जाता है. मेमोरी लीक को रोकने के लिए,renderer.cleanup()को कॉल करकेfinallyब्लॉक किया जाता है. - साइज़ बदलना: अगर डिसप्ले का डाइमेंशन बदलता है, तो
AndroidExternalSurfaceब्लॉक को रीस्टार्ट कर सकता है या कॉन्फ़िगरेशन के आधार पर अपडेट को सीधे तौर पर मैनेज कर सकता है. इसलिए, रेंडरर हमेशा मान्य बफ़र में लिखता है.
डीबग करना और पुष्टि करना
WebGPU में, इनपुट स्ट्रक्चर की पुष्टि करने और रनटाइम की गड़बड़ियों को कैप्चर करने के लिए, कुछ तरीके डिज़ाइन किए गए हैं.
- Logcat: पुष्टि करने में हुई गड़बड़ियों की जानकारी, Android Logcat में प्रिंट की जाती है.
- गड़बड़ी के स्कोप:
[device.pushErrorScope()](/reference/kotlin/androidx/webgpu/GPUDevice#pushErrorScope(kotlin.Int))और `device.popErrorScope() ब्लॉक में GPU कमांड को शामिल करके, खास गड़बड़ियों को कैप्चर किया जा सकता है.
device.pushErrorScope(ErrorFilter.Validation)
// ... potentially incorrect code ...
device.popErrorScope { status, type, message ->
if (status == PopErrorScopeStatus.Success && type != ErrorType.NoError) {
Log.e("WebGPU", "Validation Error: $message")
}
}
परफ़ॉर्मेंस के बारे में सलाह
WebGPU में प्रोग्रामिंग करते समय, परफ़ॉर्मेंस से जुड़ी समस्याओं से बचने के लिए इन बातों का ध्यान रखें:
- हर फ़्रेम के लिए ऑब्जेक्ट बनाने से बचें: ऐप्लिकेशन सेटअप के दौरान, पाइपलाइन
(
GPURenderPipeline), बाइंड ग्रुप लेआउट, और शेडर मॉड्यूल को एक बार इंस्टैंटिएट करें, ताकि उनका ज़्यादा से ज़्यादा बार इस्तेमाल किया जा सके. - बफ़र के इस्तेमाल को ऑप्टिमाइज़ करें: हर फ़्रेम के लिए नए बफ़र बनाने के बजाय,
GPUQueue.writeBufferके ज़रिए मौजूदाGPUBuffersके कॉन्टेंट को अपडेट करें. - स्टेट में होने वाले बदलावों को कम करें: एक ही पाइपलाइन शेयर करने वाले ड्रॉ कॉल को ग्रुप करें और ड्राइवर के ओवरहेड को कम करने के लिए, ग्रुप को बाइंड करें. इससे रेंडरिंग की परफ़ॉर्मेंस बेहतर होती है.