From 5bc109853190a56cf0d8d1d9f54669746fcbec1b Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 10 Sep 2025 16:58:15 +0200 Subject: [PATCH 1/2] :wrench: --- packages/webgpu/apple/RNWGUIKit.h | 2 +- packages/webgpu/cpp/jsi/RNFHybridObject.h | 6 ++ packages/webgpu/cpp/jsi/RNFJSIConverter.h | 7 +- packages/webgpu/cpp/rnwgpu/api/GPUBindGroup.h | 7 ++ .../cpp/rnwgpu/api/GPUBindGroupLayout.h | 7 ++ packages/webgpu/cpp/rnwgpu/api/GPUBuffer.h | 2 + .../cpp/rnwgpu/api/GPUCanvasContext.cpp | 2 +- .../cpp/rnwgpu/api/GPUComputePipeline.h | 7 ++ packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h | 21 +++++ packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp | 3 +- .../cpp/rnwgpu/api/GPURenderPassEncoder.cpp | 6 +- .../webgpu/cpp/rnwgpu/api/GPURenderPipeline.h | 8 ++ .../webgpu/cpp/rnwgpu/api/GPUShaderModule.cpp | 2 +- .../webgpu/cpp/rnwgpu/api/GPUShaderModule.h | 8 ++ packages/webgpu/cpp/rnwgpu/api/GPUTexture.h | 76 +++++++++++++++++++ packages/webgpu/cpp/rnwgpu/api/ImageBitmap.h | 2 + packages/webgpu/package.json | 2 +- 17 files changed, 159 insertions(+), 9 deletions(-) diff --git a/packages/webgpu/apple/RNWGUIKit.h b/packages/webgpu/apple/RNWGUIKit.h index 459331bb0..d139c848e 100644 --- a/packages/webgpu/apple/RNWGUIKit.h +++ b/packages/webgpu/apple/RNWGUIKit.h @@ -13,4 +13,4 @@ typedef UIView RNWGPlatformView; typedef NSView RNWGPlatformView; #endif -#endif // PACKAGES_WEBGPU_APPLE_RNWGUIKIT_H_ +#endif // PACKAGES_WEBGPU_APPLE_RNWGUIKIT_H_ diff --git a/packages/webgpu/cpp/jsi/RNFHybridObject.h b/packages/webgpu/cpp/jsi/RNFHybridObject.h index 56cf0c407..0a644b7aa 100644 --- a/packages/webgpu/cpp/jsi/RNFHybridObject.h +++ b/packages/webgpu/cpp/jsi/RNFHybridObject.h @@ -65,6 +65,12 @@ class HybridObject : public jsi::HostObject, public std::enable_shared_from_this */ virtual std::string toString(jsi::Runtime& runtime); + /** + * Get the memory pressure of this HostObject in bytes. + * This is used to inform the JavaScript runtime about memory usage for garbage collection. + */ + virtual size_t getMemoryPressure() { return 1024; } + private: static constexpr auto TAG = "HybridObject"; int _instanceId = 1; diff --git a/packages/webgpu/cpp/jsi/RNFJSIConverter.h b/packages/webgpu/cpp/jsi/RNFJSIConverter.h index 14daba23f..c2027232e 100644 --- a/packages/webgpu/cpp/jsi/RNFJSIConverter.h +++ b/packages/webgpu/cpp/jsi/RNFJSIConverter.h @@ -446,7 +446,12 @@ template struct JSIConverter!"); } #endif - return jsi::Object::createFromHostObject(runtime, arg); + auto result = jsi::Object::createFromHostObject(runtime, arg); + auto memoryPressure = arg->getMemoryPressure(); + if (memoryPressure > 0) { + result.setExternalMemoryPressure(runtime, memoryPressure); + } + return result; } }; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUBindGroup.h b/packages/webgpu/cpp/rnwgpu/api/GPUBindGroup.h index 5dbd07b24..5a199b009 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUBindGroup.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUBindGroup.h @@ -37,6 +37,13 @@ class GPUBindGroup : public m::HybridObject { inline const wgpu::BindGroup get() { return _instance; } + size_t getMemoryPressure() override { + // Bind groups store resource bindings and descriptor state + // They reference buffers, textures, samplers, etc. + // Estimate: 1KB per bind group (descriptor tables and binding state) + return 1024; + } + private: wgpu::BindGroup _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUBindGroupLayout.h b/packages/webgpu/cpp/rnwgpu/api/GPUBindGroupLayout.h index c5c41f665..95981cacc 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUBindGroupLayout.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUBindGroupLayout.h @@ -38,6 +38,13 @@ class GPUBindGroupLayout : public m::HybridObject { inline const wgpu::BindGroupLayout get() { return _instance; } + size_t getMemoryPressure() override { + // Bind group layouts define the structure/schema for bind groups + // They store binding descriptors, types, and validation info + // Estimate: 512 bytes per layout (smaller than actual bind groups) + return 512; + } + private: wgpu::BindGroupLayout _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUBuffer.h b/packages/webgpu/cpp/rnwgpu/api/GPUBuffer.h index 7b54a9973..b37f350ba 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUBuffer.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUBuffer.h @@ -62,6 +62,8 @@ class GPUBuffer : public m::HybridObject { inline const wgpu::Buffer get() { return _instance; } + size_t getMemoryPressure() override { return static_cast(getSize()); } + private: wgpu::Buffer _instance; std::shared_ptr _async; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp index 66fe437f2..b6f7f0aa2 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp @@ -1,7 +1,7 @@ #include "GPUCanvasContext.h" -#include #include "Convertors.h" #include "RNWebGPUManager.h" +#include #ifdef __APPLE__ #include "dawn/native/MetalBackend.h" diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h b/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h index da3e9cca8..6498fcd8c 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h @@ -45,6 +45,13 @@ class GPUComputePipeline : public m::HybridObject { inline const wgpu::ComputePipeline get() { return _instance; } + size_t getMemoryPressure() override { + // Compute pipelines contain compiled compute shader state and + // driver-specific optimized code + // Estimate: 16KB for a typical compute pipeline (single compute shader) + return 16 * 1024; + } + private: wgpu::ComputePipeline _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h b/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h index 97457684b..1f5af5694 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h @@ -44,6 +44,27 @@ class GPUQuerySet : public m::HybridObject { inline const wgpu::QuerySet get() { return _instance; } + size_t getMemoryPressure() override { + uint32_t count = getCount(); + wgpu::QueryType type = getType(); + + // Estimate bytes per query based on type + size_t bytesPerQuery = 8; // Default estimate + switch (type) { + case wgpu::QueryType::Occlusion: + bytesPerQuery = 8; // 64-bit counter + break; + case wgpu::QueryType::Timestamp: + bytesPerQuery = 8; // 64-bit timestamp + break; + default: + bytesPerQuery = 8; // Safe default + break; + } + + return static_cast(count) * bytesPerQuery; + } + private: wgpu::QuerySet _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp index 6cbb5d897..f9a5a8933 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUQueue.cpp @@ -40,7 +40,8 @@ void GPUQueue::writeBuffer(std::shared_ptr buffer, // Note that in the JS semantics of WebGPU, writeBuffer works in number of // elements of the typed arrays. - if (dataOffsetElements > static_cast(src.size / src.bytesPerElement)) { + if (dataOffsetElements > + static_cast(src.size / src.bytesPerElement)) { throw std::runtime_error("dataOffset is larger than data's size."); return; } diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp index 5a5825589..d222aab6c 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp @@ -1,9 +1,9 @@ -#include -#include #include +#include +#include -#include "GPURenderPassEncoder.h" #include "Convertors.h" +#include "GPURenderPassEncoder.h" namespace rnwgpu { diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h b/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h index 11f261352..ef87608a5 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h @@ -44,6 +44,14 @@ class GPURenderPipeline : public m::HybridObject { inline const wgpu::RenderPipeline get() { return _instance; } + size_t getMemoryPressure() override { + // Render pipelines contain compiled shader state, vertex/fragment shaders, + // render state, and driver-specific optimized code + // Estimate: 24KB for a typical render pipeline with vertex + fragment + // shaders + return 24 * 1024; + } + private: wgpu::RenderPipeline _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.cpp index 214adc013..b3b1e8c65 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.cpp @@ -1,7 +1,7 @@ #include "GPUShaderModule.h" -#include #include +#include namespace rnwgpu { diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h index d2c0ce317..0c7c9a932 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h @@ -48,6 +48,14 @@ class GPUShaderModule : public m::HybridObject { inline const wgpu::ShaderModule get() { return _instance; } + size_t getMemoryPressure() override { + // Estimate memory usage for compiled shader module + // Shaders can vary widely, but a reasonable estimate is 8-16KB for typical + // shaders Complex shaders (with many uniforms, textures, or computations) + // can be much larger + return 12 * 1024; // 12KB estimate for average shader + } + private: wgpu::ShaderModule _instance; std::shared_ptr _async; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h b/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h index 494ba1378..43658e5b6 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -64,6 +65,81 @@ class GPUTexture : public m::HybridObject { inline const wgpu::Texture get() { return _instance; } + size_t getMemoryPressure() override { + // Calculate approximate memory usage based on texture properties + uint32_t width = getWidth(); + uint32_t height = getHeight(); + uint32_t depthOrArrayLayers = getDepthOrArrayLayers(); + uint32_t mipLevelCount = getMipLevelCount(); + uint32_t sampleCount = getSampleCount(); + + // Estimate bytes per pixel based on format + // This is a simplified estimate - actual values depend on the specific + // format + size_t bytesPerPixel = 4; // Default to RGBA8 format + wgpu::TextureFormat format = getFormat(); + switch (format) { + case wgpu::TextureFormat::R8Unorm: + case wgpu::TextureFormat::R8Snorm: + case wgpu::TextureFormat::R8Uint: + case wgpu::TextureFormat::R8Sint: + bytesPerPixel = 1; + break; + case wgpu::TextureFormat::R16Uint: + case wgpu::TextureFormat::R16Sint: + case wgpu::TextureFormat::R16Float: + case wgpu::TextureFormat::RG8Unorm: + case wgpu::TextureFormat::RG8Snorm: + case wgpu::TextureFormat::RG8Uint: + case wgpu::TextureFormat::RG8Sint: + bytesPerPixel = 2; + break; + case wgpu::TextureFormat::RGBA8Unorm: + case wgpu::TextureFormat::RGBA8UnormSrgb: + case wgpu::TextureFormat::RGBA8Snorm: + case wgpu::TextureFormat::RGBA8Uint: + case wgpu::TextureFormat::RGBA8Sint: + case wgpu::TextureFormat::BGRA8Unorm: + case wgpu::TextureFormat::BGRA8UnormSrgb: + case wgpu::TextureFormat::RGB10A2Unorm: + case wgpu::TextureFormat::R32Float: + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::RG16Uint: + case wgpu::TextureFormat::RG16Sint: + case wgpu::TextureFormat::RG16Float: + bytesPerPixel = 4; + break; + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::RGBA16Uint: + case wgpu::TextureFormat::RGBA16Sint: + case wgpu::TextureFormat::RGBA16Float: + bytesPerPixel = 8; + break; + case wgpu::TextureFormat::RGBA32Float: + case wgpu::TextureFormat::RGBA32Uint: + case wgpu::TextureFormat::RGBA32Sint: + bytesPerPixel = 16; + break; + default: + bytesPerPixel = 4; // Safe default + break; + } + + // Calculate total memory for all mip levels + size_t totalMemory = 0; + for (uint32_t mip = 0; mip < mipLevelCount; ++mip) { + uint32_t mipWidth = std::max(1u, width >> mip); + uint32_t mipHeight = std::max(1u, height >> mip); + totalMemory += static_cast(mipWidth) * mipHeight * + depthOrArrayLayers * bytesPerPixel * sampleCount; + } + + return totalMemory; + } + private: wgpu::Texture _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/ImageBitmap.h b/packages/webgpu/cpp/rnwgpu/api/ImageBitmap.h index 3c8807b1e..6276c25ca 100644 --- a/packages/webgpu/cpp/rnwgpu/api/ImageBitmap.h +++ b/packages/webgpu/cpp/rnwgpu/api/ImageBitmap.h @@ -27,6 +27,8 @@ class ImageBitmap : public margelo::HybridObject { registerHybridGetter("height", &ImageBitmap::getHeight, this); } + size_t getMemoryPressure() override { return getSize(); } + private: ImageData _imageData; }; diff --git a/packages/webgpu/package.json b/packages/webgpu/package.json index daaa57ed3..e0d409824 100644 --- a/packages/webgpu/package.json +++ b/packages/webgpu/package.json @@ -1,6 +1,6 @@ { "name": "react-native-wgpu", - "version": "0.2.2", + "version": "0.2.3", "description": "React Native WebGPU", "main": "lib/commonjs/index", "module": "lib/module/index", From 4fe7f499ce79eb65b3b8816b587aab43b1b97090 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 10 Sep 2025 17:30:06 +0200 Subject: [PATCH 2/2] :wrench: --- apps/example/ios/Podfile.lock | 4 ++-- packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 178e151d4..a06dd9ecd 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -1433,7 +1433,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-wgpu (0.2.2): + - react-native-wgpu (0.2.3): - DoubleConversion - glog - hermes-engine @@ -2246,7 +2246,7 @@ SPEC CHECKSUMS: React-microtasksnativemodule: ca2804a25fdcefffa0aa942aa23ab53b99614a34 react-native-safe-area-context: 00d03dc688ba86664be66f9e3f203fc7d747d899 react-native-skia: 443d0725a6cbbcce886edb96b591935eb3bc36d8 - react-native-wgpu: e7754c8f25598bfc7e77e5938acce1445f8f2f2b + react-native-wgpu: 282b5bac022287804e6a7b064f903b4e273c7024 React-NativeModulesApple: 452b86b29fae99ed0a4015dca3ad9cd222f88abf React-oscompat: ef5df1c734f19b8003e149317d041b8ce1f7d29c React-perflogger: 6fd2f6811533e9c19a61e855c3033eecbf4ad2a0 diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp index d222aab6c..d7bab5cc5 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.cpp @@ -2,8 +2,8 @@ #include #include -#include "Convertors.h" #include "GPURenderPassEncoder.h" +#include "Convertors.h" namespace rnwgpu { @@ -162,4 +162,4 @@ void GPURenderPassEncoder::drawIndexedIndirect( _instance.DrawIndexedIndirect(b, indirectOffset); } -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu