diff --git a/packages/webgpu/cpp/jsi/RNFHybridObject.h b/packages/webgpu/cpp/jsi/RNFHybridObject.h index 2e345606..7bcfc5b3 100644 --- a/packages/webgpu/cpp/jsi/RNFHybridObject.h +++ b/packages/webgpu/cpp/jsi/RNFHybridObject.h @@ -77,7 +77,7 @@ class HybridObject : public jsi::HostObject, public std::enable_shared_from_this * 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; } + virtual size_t getMemoryPressure() = 0; private: static constexpr auto TAG = "HybridObject"; diff --git a/packages/webgpu/cpp/jsi/RNFPointerHolder.h b/packages/webgpu/cpp/jsi/RNFPointerHolder.h index f8434597..8517259c 100644 --- a/packages/webgpu/cpp/jsi/RNFPointerHolder.h +++ b/packages/webgpu/cpp/jsi/RNFPointerHolder.h @@ -16,6 +16,16 @@ namespace margelo { namespace jsi = facebook::jsi; template class PointerHolder : public HybridObject { +public: + size_t getMemoryPressure() override { + std::unique_lock lock(_mutex); + if (_pointer == nullptr) { + return 0; + } + // Default to a small-but-nonzero floor so holders contribute to pressure. + return 64 * 1024; // 64KB + } + protected: // no default constructor PointerHolder() = delete; diff --git a/packages/webgpu/cpp/rnwgpu/api/Canvas.h b/packages/webgpu/cpp/rnwgpu/api/Canvas.h index 25a3a9c1..48e0c9b2 100644 --- a/packages/webgpu/cpp/rnwgpu/api/Canvas.h +++ b/packages/webgpu/cpp/rnwgpu/api/Canvas.h @@ -44,6 +44,8 @@ class Canvas : public m::HybridObject { registerHybridSetter("height", &Canvas::setHeight, this); } + size_t getMemoryPressure() override { return sizeof(Canvas); } + private: void *_surface; int _width; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPU.h b/packages/webgpu/cpp/rnwgpu/api/GPU.h index a94e66c6..cd841239 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPU.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPU.h @@ -48,6 +48,11 @@ class GPU : public m::HybridObject { inline const wgpu::Instance get() { return _instance; } + size_t getMemoryPressure() override { + // Instance discovery spins up adapter caches and driver state. + return 512 * 1024; // 512KB baseline + } + private: wgpu::Instance _instance; std::shared_ptr _async; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp index e4bb7ca9..81bad639 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.cpp @@ -82,16 +82,16 @@ async::AsyncTaskHandle GPUAdapter::requestDevice( auto creationRuntime = getCreationRuntime(); return _async->postTask( [this, aDescriptor, descriptor, label = std::move(label), - deviceLostBinding, creationRuntime]( - const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { + deviceLostBinding, + creationRuntime](const async::AsyncTaskHandle::ResolveFunction &resolve, + const async::AsyncTaskHandle::RejectFunction &reject) { (void)descriptor; _instance.RequestDevice( &aDescriptor, wgpu::CallbackMode::AllowProcessEvents, - [asyncRunner = _async, resolve, reject, label, - creationRuntime, deviceLostBinding]( - wgpu::RequestDeviceStatus status, wgpu::Device device, - wgpu::StringView message) mutable { + [asyncRunner = _async, resolve, reject, label, creationRuntime, + deviceLostBinding](wgpu::RequestDeviceStatus status, + wgpu::Device device, + wgpu::StringView message) mutable { if (message.length) { fprintf(stderr, "%s", message.data); } diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.h b/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.h index ff2a3819..977c0ead 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUAdapter.h @@ -48,6 +48,8 @@ class GPUAdapter : public m::HybridObject { inline const wgpu::Adapter get() { return _instance; } + size_t getMemoryPressure() override { return 1024; } + private: wgpu::Adapter _instance; std::shared_ptr _async; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUAdapterInfo.h b/packages/webgpu/cpp/rnwgpu/api/GPUAdapterInfo.h index 8ae0d35d..781ca20c 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUAdapterInfo.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUAdapterInfo.h @@ -44,6 +44,12 @@ class GPUAdapterInfo : public m::HybridObject { &GPUAdapterInfo::getIsFallbackAdapter, this); } + size_t getMemoryPressure() override { + return sizeof(GPUAdapterInfo) + _vendor.capacity() + + _architecture.capacity() + _device.capacity() + + _description.capacity(); + } + private: std::string _vendor; std::string _architecture; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.h b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.h index e425a072..8114da76 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -46,6 +47,32 @@ class GPUCanvasContext : public m::HybridObject { registerHybridMethod("present", &GPUCanvasContext::present, this); } + size_t getMemoryPressure() override { + int width = 0; + int height = 0; + + if (_surfaceInfo) { + auto size = _surfaceInfo->getSize(); + width = size.width; + height = size.height; + } + + if (_canvas) { + width = std::max(width, _canvas->getWidth()); + height = std::max(height, _canvas->getHeight()); + } + + if (width <= 0 || height <= 0) { + return 4 * 1024 * 1024; // default to 4MB when size is unknown + } + + constexpr size_t kBytesPerPixel = 4; // RGBA8 fallback + constexpr size_t kFloor = 4 * 1024 * 1024; + size_t estimated = static_cast(width) * + static_cast(height) * kBytesPerPixel; + return std::max(estimated, kFloor); + } + // TODO: is this ok? inline const wgpu::Surface get() { return nullptr; } void configure(std::shared_ptr configuration); diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCommandBuffer.h b/packages/webgpu/cpp/rnwgpu/api/GPUCommandBuffer.h index 9ef9a95f..914cff2c 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCommandBuffer.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCommandBuffer.h @@ -35,6 +35,8 @@ class GPUCommandBuffer : public m::HybridObject { inline const wgpu::CommandBuffer get() { return _instance; } + size_t getMemoryPressure() override { return 1024 * 1024; } + private: wgpu::CommandBuffer _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCommandEncoder.h b/packages/webgpu/cpp/rnwgpu/api/GPUCommandEncoder.h index 61616017..25f2e4c6 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCommandEncoder.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCommandEncoder.h @@ -100,6 +100,8 @@ class GPUCommandEncoder : public m::HybridObject { inline const wgpu::CommandEncoder get() { return _instance; } + size_t getMemoryPressure() override { return 1024 * 1024; } + private: wgpu::CommandEncoder _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCompilationInfo.h b/packages/webgpu/cpp/rnwgpu/api/GPUCompilationInfo.h index e3dc3f4a..d10e7330 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCompilationInfo.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCompilationInfo.h @@ -36,6 +36,15 @@ class GPUCompilationInfo : public m::HybridObject { registerHybridGetter("messages", &GPUCompilationInfo::getMessages, this); } + size_t getMemoryPressure() override { + size_t total = sizeof(GPUCompilationInfo) + + _messages.capacity() * sizeof(GPUCompilationMessage); + for (const auto &message : _messages) { + total += message.message.capacity(); + } + return total; + } + private: std::vector _messages; friend class GPUShaderModule; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCompilationMessage.h b/packages/webgpu/cpp/rnwgpu/api/GPUCompilationMessage.h index b94295af..edba839b 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCompilationMessage.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCompilationMessage.h @@ -26,6 +26,10 @@ class GPUCompilationMessage : public m::HybridObject { inline const wgpu::CompilationMessage get() { return _instance; } + size_t getMemoryPressure() override { + return sizeof(wgpu::CompilationMessage); + } + private: wgpu::CompilationMessage _instance; }; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUComputePassEncoder.h b/packages/webgpu/cpp/rnwgpu/api/GPUComputePassEncoder.h index 9734d351..94cde1e4 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUComputePassEncoder.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUComputePassEncoder.h @@ -76,6 +76,8 @@ class GPUComputePassEncoder : public m::HybridObject { inline const wgpu::ComputePassEncoder get() { return _instance; } + size_t getMemoryPressure() override { return 1024; } + private: wgpu::ComputePassEncoder _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h b/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h index e8bd6d56..3605b33b 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUComputePipeline.h @@ -44,10 +44,9 @@ 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; + // Compute pipelines retain compiled shader state and backend caches. + // Overshoot intentionally to reflect the native resources they fan out to. + return 3 * 1024 * 1024; // 3MB } private: diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUDevice.h b/packages/webgpu/cpp/rnwgpu/api/GPUDevice.h index ef8ed87e..e3105db0 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUDevice.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUDevice.h @@ -151,6 +151,12 @@ class GPUDevice : public m::HybridObject { inline const wgpu::Device get() { return _instance; } + size_t getMemoryPressure() override { + // Devices keep large driver heaps, pipeline caches and residency tracking. + constexpr size_t kDeviceFloor = 8 * 1024 * 1024; // 8MB baseline + return kDeviceFloor + _label.capacity(); + } + private: friend class GPUAdapter; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUDeviceLostInfo.h b/packages/webgpu/cpp/rnwgpu/api/GPUDeviceLostInfo.h index 35feffcb..b3c79708 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUDeviceLostInfo.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUDeviceLostInfo.h @@ -30,6 +30,10 @@ class GPUDeviceLostInfo : public m::HybridObject { registerHybridGetter("message", &GPUDeviceLostInfo::getMessage, this); } + size_t getMemoryPressure() override { + return sizeof(wgpu::DeviceLostReason) + _message.capacity(); + } + private: wgpu::DeviceLostReason _reason; std::string _message; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUExternalTexture.h b/packages/webgpu/cpp/rnwgpu/api/GPUExternalTexture.h index ffca6cce..308a708e 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUExternalTexture.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUExternalTexture.h @@ -36,6 +36,12 @@ class GPUExternalTexture : public m::HybridObject { inline const wgpu::ExternalTexture get() { return _instance; } + size_t getMemoryPressure() override { + // External textures usually wrap decoder/camera surfaces (multi-MB frames). + constexpr size_t kExternalTextureFloor = 8 * 1024 * 1024; // 8MB baseline + return kExternalTextureFloor + _label.capacity(); + } + private: wgpu::ExternalTexture _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUPipelineLayout.h b/packages/webgpu/cpp/rnwgpu/api/GPUPipelineLayout.h index c42e9391..4079f98b 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUPipelineLayout.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUPipelineLayout.h @@ -35,6 +35,8 @@ class GPUPipelineLayout : public m::HybridObject { inline const wgpu::PipelineLayout get() { return _instance; } + size_t getMemoryPressure() override { return 1024; } + private: wgpu::PipelineLayout _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h b/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h index 6d14195d..f291ec28 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUQuerySet.h @@ -43,20 +43,23 @@ class GPUQuerySet : public m::HybridObject { inline const wgpu::QuerySet get() { return _instance; } size_t getMemoryPressure() override { - uint32_t count = getCount(); - wgpu::QueryType type = getType(); + const uint32_t count = getCount(); + const wgpu::QueryType type = getType(); - // Estimate bytes per query based on type - size_t bytesPerQuery = 8; // Default estimate + size_t bytesPerQuery = 16; // default to an overshoot switch (type) { case wgpu::QueryType::Occlusion: - bytesPerQuery = 8; // 64-bit counter + bytesPerQuery = 16; // occlusion result is 64-bit; pad to 16 for safety break; case wgpu::QueryType::Timestamp: - bytesPerQuery = 8; // 64-bit timestamp + bytesPerQuery = 16; // timestamps are 64-bit; double to overshoot break; + case wgpu::QueryType::PipelineStatistics: { + constexpr size_t kAssumedCountersPerQuery = 8; + bytesPerQuery = 8 * kAssumedCountersPerQuery; + break; + } default: - bytesPerQuery = 8; // Safe default break; } diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUQueue.h b/packages/webgpu/cpp/rnwgpu/api/GPUQueue.h index c01237b7..c92e4682 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUQueue.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUQueue.h @@ -71,6 +71,12 @@ class GPUQueue : public m::HybridObject { inline const wgpu::Queue get() { return _instance; } + size_t getMemoryPressure() override { + // Queues retain submitted command buffers and backend scheduling state. + constexpr size_t kQueueFloor = 1 * 1024 * 1024; // 1MB baseline + return kQueueFloor + _label.capacity(); + } + private: wgpu::Queue _instance; std::shared_ptr _async; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderBundle.h b/packages/webgpu/cpp/rnwgpu/api/GPURenderBundle.h index d59c8e42..4ee2335b 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderBundle.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderBundle.h @@ -35,6 +35,8 @@ class GPURenderBundle : public m::HybridObject { inline const wgpu::RenderBundle get() { return _instance; } + size_t getMemoryPressure() override { return 1024 * 1024; } + private: wgpu::RenderBundle _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderBundleEncoder.h b/packages/webgpu/cpp/rnwgpu/api/GPURenderBundleEncoder.h index e0abe107..1884ff44 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderBundleEncoder.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderBundleEncoder.h @@ -99,6 +99,8 @@ class GPURenderBundleEncoder : public m::HybridObject { inline const wgpu::RenderBundleEncoder get() { return _instance; } + size_t getMemoryPressure() override { return 1024 * 1024; } + private: wgpu::RenderBundleEncoder _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.h b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.h index 126bc675..7e50dfc6 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderPassEncoder.h @@ -120,6 +120,8 @@ class GPURenderPassEncoder : public m::HybridObject { inline const wgpu::RenderPassEncoder get() { return _instance; } + size_t getMemoryPressure() override { return 1024 * 1024; } + private: wgpu::RenderPassEncoder _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h b/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h index a52a91f4..ea3b0c26 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPURenderPipeline.h @@ -43,11 +43,10 @@ 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; + // Render pipelines combine multiple compiled stages plus fixed-function + // state baked by the driver. Reserve several megabytes to signal that to + // the GC. + return 3 * 1024 * 1024; // 3MB } private: diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUSampler.h b/packages/webgpu/cpp/rnwgpu/api/GPUSampler.h index dd88ae86..a6778e75 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUSampler.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUSampler.h @@ -35,6 +35,8 @@ class GPUSampler : public m::HybridObject { inline const wgpu::Sampler get() { return _instance; } + size_t getMemoryPressure() override { return 1024; } + private: wgpu::Sampler _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h index bc5be9e2..18d82142 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUShaderModule.h @@ -49,11 +49,9 @@ 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 + // Shader modules can fan out into compiled IR, reflection data and backend + // caches. Report a conservative 1MB to reflect that cost. + return 1 * 1024 * 1024; // 1MB } private: diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUSupportedLimits.h b/packages/webgpu/cpp/rnwgpu/api/GPUSupportedLimits.h index e0ecff61..b8c64de3 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUSupportedLimits.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUSupportedLimits.h @@ -144,6 +144,8 @@ class GPUSupportedLimits : public m::HybridObject { inline const wgpu::Limits get() { return _instance; } + size_t getMemoryPressure() override { return sizeof(wgpu::Limits); } + private: wgpu::Limits _instance; }; diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h b/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h index 2d45b963..53d02acd 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUTexture.h @@ -64,77 +64,192 @@ 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; - } + struct FormatMemoryInfo { + uint32_t blockWidth; + uint32_t blockHeight; + size_t bytesPerBlock; + bool isCompressed; + }; + + auto getFormatInfo = [](wgpu::TextureFormat format) -> FormatMemoryInfo { + using Info = FormatMemoryInfo; + switch (format) { + case wgpu::TextureFormat::R8Unorm: + case wgpu::TextureFormat::R8Snorm: + case wgpu::TextureFormat::R8Uint: + case wgpu::TextureFormat::R8Sint: + case wgpu::TextureFormat::Stencil8: + return {1, 1, 1, false}; + case wgpu::TextureFormat::R16Unorm: + case wgpu::TextureFormat::R16Snorm: + 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: + case wgpu::TextureFormat::Depth16Unorm: + return {1, 1, 2, false}; + case wgpu::TextureFormat::R32Float: + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::RG16Unorm: + case wgpu::TextureFormat::RG16Snorm: + case wgpu::TextureFormat::RG16Uint: + case wgpu::TextureFormat::RG16Sint: + case wgpu::TextureFormat::RG16Float: + 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::RGB10A2Uint: + case wgpu::TextureFormat::RG11B10Ufloat: + case wgpu::TextureFormat::RGB9E5Ufloat: + case wgpu::TextureFormat::Depth24Plus: + case wgpu::TextureFormat::Depth24PlusStencil8: + case wgpu::TextureFormat::Depth32Float: + case wgpu::TextureFormat::External: + return {1, 1, 4, false}; + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::RGBA16Unorm: + case wgpu::TextureFormat::RGBA16Snorm: + case wgpu::TextureFormat::RGBA16Uint: + case wgpu::TextureFormat::RGBA16Sint: + case wgpu::TextureFormat::RGBA16Float: + case wgpu::TextureFormat::Depth32FloatStencil8: + return {1, 1, 8, false}; + case wgpu::TextureFormat::RGBA32Float: + case wgpu::TextureFormat::RGBA32Uint: + case wgpu::TextureFormat::RGBA32Sint: + return {1, 1, 16, false}; + case wgpu::TextureFormat::BC1RGBAUnorm: + case wgpu::TextureFormat::BC1RGBAUnormSrgb: + case wgpu::TextureFormat::BC4RUnorm: + case wgpu::TextureFormat::BC4RSnorm: + case wgpu::TextureFormat::ETC2RGB8Unorm: + case wgpu::TextureFormat::ETC2RGB8UnormSrgb: + case wgpu::TextureFormat::ETC2RGB8A1Unorm: + case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: + case wgpu::TextureFormat::EACR11Unorm: + case wgpu::TextureFormat::EACR11Snorm: + return {4, 4, 8, true}; + case wgpu::TextureFormat::BC2RGBAUnorm: + case wgpu::TextureFormat::BC2RGBAUnormSrgb: + case wgpu::TextureFormat::BC3RGBAUnorm: + case wgpu::TextureFormat::BC3RGBAUnormSrgb: + case wgpu::TextureFormat::BC5RGUnorm: + case wgpu::TextureFormat::BC5RGSnorm: + case wgpu::TextureFormat::BC6HRGBUfloat: + case wgpu::TextureFormat::BC6HRGBFloat: + case wgpu::TextureFormat::BC7RGBAUnorm: + case wgpu::TextureFormat::BC7RGBAUnormSrgb: + case wgpu::TextureFormat::ETC2RGBA8Unorm: + case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: + case wgpu::TextureFormat::EACRG11Unorm: + case wgpu::TextureFormat::EACRG11Snorm: + return {4, 4, 16, true}; + case wgpu::TextureFormat::ASTC4x4Unorm: + case wgpu::TextureFormat::ASTC4x4UnormSrgb: + return {4, 4, 16, true}; + case wgpu::TextureFormat::ASTC5x4Unorm: + case wgpu::TextureFormat::ASTC5x4UnormSrgb: + return {5, 4, 16, true}; + case wgpu::TextureFormat::ASTC5x5Unorm: + case wgpu::TextureFormat::ASTC5x5UnormSrgb: + return {5, 5, 16, true}; + case wgpu::TextureFormat::ASTC6x5Unorm: + case wgpu::TextureFormat::ASTC6x5UnormSrgb: + return {6, 5, 16, true}; + case wgpu::TextureFormat::ASTC6x6Unorm: + case wgpu::TextureFormat::ASTC6x6UnormSrgb: + return {6, 6, 16, true}; + case wgpu::TextureFormat::ASTC8x5Unorm: + case wgpu::TextureFormat::ASTC8x5UnormSrgb: + return {8, 5, 16, true}; + case wgpu::TextureFormat::ASTC8x6Unorm: + case wgpu::TextureFormat::ASTC8x6UnormSrgb: + return {8, 6, 16, true}; + case wgpu::TextureFormat::ASTC8x8Unorm: + case wgpu::TextureFormat::ASTC8x8UnormSrgb: + return {8, 8, 16, true}; + case wgpu::TextureFormat::ASTC10x5Unorm: + case wgpu::TextureFormat::ASTC10x5UnormSrgb: + return {10, 5, 16, true}; + case wgpu::TextureFormat::ASTC10x6Unorm: + case wgpu::TextureFormat::ASTC10x6UnormSrgb: + return {10, 6, 16, true}; + case wgpu::TextureFormat::ASTC10x8Unorm: + case wgpu::TextureFormat::ASTC10x8UnormSrgb: + return {10, 8, 16, true}; + case wgpu::TextureFormat::ASTC10x10Unorm: + case wgpu::TextureFormat::ASTC10x10UnormSrgb: + return {10, 10, 16, true}; + case wgpu::TextureFormat::ASTC12x10Unorm: + case wgpu::TextureFormat::ASTC12x10UnormSrgb: + return {12, 10, 16, true}; + case wgpu::TextureFormat::ASTC12x12Unorm: + case wgpu::TextureFormat::ASTC12x12UnormSrgb: + return {12, 12, 16, true}; + case wgpu::TextureFormat::R8BG8Biplanar420Unorm: + case wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm: + case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm: + case wgpu::TextureFormat::R8BG8Biplanar422Unorm: + case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm: + return {1, 1, 2, false}; + case wgpu::TextureFormat::R8BG8Biplanar444Unorm: + return {1, 1, 3, false}; + case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm: + return {1, 1, 6, false}; + case wgpu::TextureFormat::Undefined: + default: + return {1, 1, 4, false}; + } + }; + + const uint32_t width = getWidth(); + const uint32_t height = getHeight(); + const uint32_t depthOrArrayLayers = getDepthOrArrayLayers(); + const uint32_t mipLevelCount = getMipLevelCount(); + const uint32_t sampleCount = std::max(1u, getSampleCount()); + const bool is3D = getDimension() == wgpu::TextureDimension::e3D; + + FormatMemoryInfo info = getFormatInfo(getFormat()); - // 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; + const uint32_t mipWidth = std::max(1u, width >> mip); + const uint32_t mipHeight = std::max(1u, height >> mip); + const uint32_t mipDepthOrLayers = + is3D ? std::max(1u, depthOrArrayLayers >> mip) : depthOrArrayLayers; + const size_t layerMultiplier = + static_cast(mipDepthOrLayers) * sampleCount; + + if (info.isCompressed) { + const uint32_t blocksWide = + (mipWidth + info.blockWidth - 1) / info.blockWidth; + const uint32_t blocksHigh = + (mipHeight + info.blockHeight - 1) / info.blockHeight; + totalMemory += static_cast(blocksWide) * blocksHigh * + info.bytesPerBlock * layerMultiplier; + } else { + totalMemory += static_cast(mipWidth) * mipHeight * + info.bytesPerBlock * layerMultiplier; + } } + constexpr size_t kAlignment = 4 * 1024; // keep GC pressure conservative + if (totalMemory == 0) { + totalMemory = kAlignment; + } else { + totalMemory = ((totalMemory + kAlignment - 1) / kAlignment) * kAlignment; + } return totalMemory; } diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUTextureView.h b/packages/webgpu/cpp/rnwgpu/api/GPUTextureView.h index 482c53c6..90ce9563 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUTextureView.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPUTextureView.h @@ -35,6 +35,8 @@ class GPUTextureView : public m::HybridObject { inline const wgpu::TextureView get() { return _instance; } + size_t getMemoryPressure() override { return 1024; } + private: wgpu::TextureView _instance; std::string _label; diff --git a/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h b/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h index 9f6ea1f8..3f8fa420 100644 --- a/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h +++ b/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h @@ -67,6 +67,8 @@ class RNWebGPU : public m::HybridObject { &RNWebGPU::MakeWebGPUCanvasContext, this); } + size_t getMemoryPressure() override { return sizeof(RNWebGPU); } + private: std::shared_ptr _gpu; std::shared_ptr _platformContext; diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h index f833c125..87b130c2 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h @@ -39,5 +39,7 @@ class GPUBufferUsage : public m::HybridObject { registerHybridGetter("INDIRECT", &GPUBufferUsage::Indirect, this); registerHybridGetter("QUERY_RESOLVE", &GPUBufferUsage::QueryResolve, this); } + + size_t getMemoryPressure() override { return sizeof(GPUBufferUsage); } }; -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUColorWrite.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUColorWrite.h index 569b417c..6fe77024 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUColorWrite.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUColorWrite.h @@ -27,5 +27,7 @@ class GPUColorWrite : public m::HybridObject { registerHybridGetter("ALPHA", &GPUColorWrite::Alpha, this); registerHybridGetter("ALL", &GPUColorWrite::All, this); } + + size_t getMemoryPressure() override { return sizeof(GPUColorWrite); } }; -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUMapMode.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUMapMode.h index dce03b5d..015d11cb 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUMapMode.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUMapMode.h @@ -21,5 +21,7 @@ class GPUMapMode : public m::HybridObject { registerHybridGetter("READ", &GPUMapMode::Read, this); registerHybridGetter("WRITE", &GPUMapMode::Write, this); } + + size_t getMemoryPressure() override { return sizeof(GPUMapMode); } }; -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUShaderStage.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUShaderStage.h index 4bf78bad..31bc2209 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUShaderStage.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUShaderStage.h @@ -23,5 +23,7 @@ class GPUShaderStage : public m::HybridObject { registerHybridGetter("FRAGMENT", &GPUShaderStage::Fragment, this); registerHybridGetter("COMPUTE", &GPUShaderStage::Compute, this); } + + size_t getMemoryPressure() override { return sizeof(GPUShaderStage); } }; -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h index 563b6200..1934ee6e 100644 --- a/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h +++ b/packages/webgpu/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h @@ -36,5 +36,7 @@ class GPUTextureUsage : public m::HybridObject { registerHybridGetter("RENDER_ATTACHMENT", &GPUTextureUsage::RenderAttachment, this); } + + size_t getMemoryPressure() override { return sizeof(GPUTextureUsage); } }; -} // namespace rnwgpu \ No newline at end of file +} // namespace rnwgpu