From e339788df2613650ce88b91f4b5d0dd9eb6c3fdd Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 29 Jul 2026 10:28:45 +0200 Subject: [PATCH 1/3] =?UTF-8?q?fix(=F0=9F=97=BF):=20Skia=20Graphite=20WebG?= =?UTF-8?q?PU=20migration=20(#3979)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/docs/getting-started/installation.md | 24 +- apps/example/ios/Podfile | 18 +- apps/example/ios/Podfile.lock | 174 +- apps/example/jest.config.mjs | 1 + apps/example/macos/Podfile | 15 +- apps/example/macos/Podfile.lock | 4 +- apps/example/package.json | 1 + .../Examples/WebGPU/ImportExternalTexture.tsx | 38 +- .../src/Examples/WebGPU/PendingInterop.tsx | 43 + .../src/Examples/WebGPU/TexturedCube.tsx | 55 +- apps/example/src/Examples/WebGPU/Triangle.tsx | 119 +- .../src/Examples/WebGPU/Wireframes.tsx | 5 +- apps/example/src/Home/HomeScreen.tsx | 10 +- apps/example/src/Tests/useClient.ts | 11 +- externals/skia | 2 +- packages/skia/android/CMakeLists.txt | 48 +- packages/skia/android/build.gradle | 33 + .../skia/android/cpp/jni/JniWebGPUView.cpp | 112 - .../cpp/rnskia-android/SkiaPlatformContext.h | 26 - .../reactnative/skia/RNSkiaPackage.java | 3 +- .../reactnative/skia/WebGPUSurfaceView.java | 43 - .../reactnative/skia/WebGPUTextureView.java | 50 - .../shopify/reactnative/skia/WebGPUView.java | 98 - .../reactnative/skia/WebGPUViewAPI.java | 19 - .../reactnative/skia/WebGPUViewManager.java | 58 - .../skia/apple/RNWebGPUAppleNativeBuffer.mm | 33 - packages/skia/apple/SkiaPlatformContext.h | 20 - packages/skia/apple/SkiaPlatformContext.mm | 21 - packages/skia/apple/SkiaWebGPUView.mm | 81 - packages/skia/apple/WebGPUMetalView.mm | 136 -- packages/skia/cpp/api/JsiSkApi.h | 41 +- packages/skia/cpp/api/JsiSkImageFactory.h | 78 +- packages/skia/cpp/jsi/JSIConverter.h | 31 - packages/skia/cpp/rnskia/RNDawnContext.h | 20 +- packages/skia/cpp/rnskia/RNDawnInterop.cpp | 19 + packages/skia/cpp/rnskia/RNDawnUtils.h | 19 +- packages/skia/cpp/rnskia/RNSkManager.cpp | 167 +- packages/skia/cpp/rnwgpu/ArrayBuffer.h | 116 - packages/skia/cpp/rnwgpu/Canvas.h | 52 - packages/skia/cpp/rnwgpu/PlatformContext.h | 18 - packages/skia/cpp/rnwgpu/SurfaceRegistry.h | 605 ----- .../skia/cpp/rnwgpu/api/AppleNativeBuffer.h | 22 - packages/skia/cpp/rnwgpu/api/Convertors.h | 783 ------- packages/skia/cpp/rnwgpu/api/External.h | 12 - packages/skia/cpp/rnwgpu/api/GPU.cpp | 162 -- packages/skia/cpp/rnwgpu/api/GPU.h | 60 - packages/skia/cpp/rnwgpu/api/GPUAdapter.cpp | 239 -- packages/skia/cpp/rnwgpu/api/GPUAdapter.h | 60 - packages/skia/cpp/rnwgpu/api/GPUAdapterInfo.h | 57 - packages/skia/cpp/rnwgpu/api/GPUBindGroup.cpp | 3 - packages/skia/cpp/rnwgpu/api/GPUBindGroup.h | 51 - .../skia/cpp/rnwgpu/api/GPUBindGroupLayout.h | 52 - packages/skia/cpp/rnwgpu/api/GPUBuffer.cpp | 107 - packages/skia/cpp/rnwgpu/api/GPUBuffer.h | 88 - .../skia/cpp/rnwgpu/api/GPUCanvasContext.cpp | 75 - .../skia/cpp/rnwgpu/api/GPUCanvasContext.h | 70 - .../skia/cpp/rnwgpu/api/GPUCommandBuffer.h | 45 - .../skia/cpp/rnwgpu/api/GPUCommandEncoder.cpp | 179 -- .../skia/cpp/rnwgpu/api/GPUCommandEncoder.h | 111 - .../skia/cpp/rnwgpu/api/GPUCompilationInfo.h | 79 - .../cpp/rnwgpu/api/GPUCompilationMessage.h | 36 - .../cpp/rnwgpu/api/GPUComputePassEncoder.cpp | 60 - .../cpp/rnwgpu/api/GPUComputePassEncoder.h | 85 - .../cpp/rnwgpu/api/GPUComputePipeline.cpp | 12 - .../skia/cpp/rnwgpu/api/GPUComputePipeline.h | 60 - packages/skia/cpp/rnwgpu/api/GPUDevice.cpp | 613 ----- packages/skia/cpp/rnwgpu/api/GPUDevice.h | 258 --- .../skia/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp | 7 - .../skia/cpp/rnwgpu/api/GPUDeviceLostInfo.h | 40 - packages/skia/cpp/rnwgpu/api/GPUError.h | 35 - packages/skia/cpp/rnwgpu/api/GPUExtent3D.h | 66 - .../cpp/rnwgpu/api/GPUExternalTexture.cpp | 139 -- .../skia/cpp/rnwgpu/api/GPUExternalTexture.h | 95 - packages/skia/cpp/rnwgpu/api/GPUFeatures.h | 203 -- .../skia/cpp/rnwgpu/api/GPUInternalError.h | 31 - packages/skia/cpp/rnwgpu/api/GPUOrigin2D.h | 55 - packages/skia/cpp/rnwgpu/api/GPUOrigin3D.h | 62 - .../skia/cpp/rnwgpu/api/GPUOutOfMemoryError.h | 33 - .../skia/cpp/rnwgpu/api/GPUPipelineLayout.h | 45 - packages/skia/cpp/rnwgpu/api/GPUQuerySet.cpp | 11 - packages/skia/cpp/rnwgpu/api/GPUQuerySet.h | 73 - packages/skia/cpp/rnwgpu/api/GPUQueue.cpp | 179 -- packages/skia/cpp/rnwgpu/api/GPUQueue.h | 84 - .../skia/cpp/rnwgpu/api/GPURenderBundle.h | 44 - .../cpp/rnwgpu/api/GPURenderBundleEncoder.cpp | 131 -- .../cpp/rnwgpu/api/GPURenderBundleEncoder.h | 110 - .../cpp/rnwgpu/api/GPURenderPassEncoder.cpp | 165 -- .../cpp/rnwgpu/api/GPURenderPassEncoder.h | 130 -- .../skia/cpp/rnwgpu/api/GPURenderPipeline.cpp | 13 - .../skia/cpp/rnwgpu/api/GPURenderPipeline.h | 61 - packages/skia/cpp/rnwgpu/api/GPUSampler.h | 44 - .../skia/cpp/rnwgpu/api/GPUShaderModule.cpp | 56 - .../skia/cpp/rnwgpu/api/GPUShaderModule.h | 66 - .../skia/cpp/rnwgpu/api/GPUSharedFence.cpp | 80 - packages/skia/cpp/rnwgpu/api/GPUSharedFence.h | 53 - .../cpp/rnwgpu/api/GPUSharedTextureMemory.cpp | 135 -- .../cpp/rnwgpu/api/GPUSharedTextureMemory.h | 75 - .../cpp/rnwgpu/api/GPUSupportedLimits.cpp | 129 -- .../skia/cpp/rnwgpu/api/GPUSupportedLimits.h | 131 -- packages/skia/cpp/rnwgpu/api/GPUTexture.cpp | 47 - packages/skia/cpp/rnwgpu/api/GPUTexture.h | 162 -- packages/skia/cpp/rnwgpu/api/GPUTextureView.h | 44 - .../cpp/rnwgpu/api/GPUUncapturedErrorEvent.h | 60 - .../skia/cpp/rnwgpu/api/GPUValidationError.h | 32 - packages/skia/cpp/rnwgpu/api/ImageBitmap.h | 62 - .../skia/cpp/rnwgpu/api/NativeBufferUtils.h | 87 - packages/skia/cpp/rnwgpu/api/RNWebGPU.h | 82 - .../skia/cpp/rnwgpu/api/WebGPUConstants.h | 36 - .../api/descriptors/GPUBindGroupDescriptor.h | 64 - .../api/descriptors/GPUBindGroupEntry.h | 78 - .../GPUBindGroupLayoutDescriptor.h | 56 - .../api/descriptors/GPUBindGroupLayoutEntry.h | 97 - .../api/descriptors/GPUBlendComponent.h | 57 - .../rnwgpu/api/descriptors/GPUBlendState.h | 52 - .../rnwgpu/api/descriptors/GPUBufferBinding.h | 56 - .../api/descriptors/GPUBufferBindingLayout.h | 56 - .../api/descriptors/GPUBufferDescriptor.h | 59 - .../rnwgpu/api/descriptors/GPUBufferUsage.h | 39 - .../api/descriptors/GPUCanvasConfiguration.h | 76 - .../cpp/rnwgpu/api/descriptors/GPUColor.h | 66 - .../api/descriptors/GPUColorTargetState.h | 58 - .../rnwgpu/api/descriptors/GPUColorWrite.h | 29 - .../descriptors/GPUCommandBufferDescriptor.h | 45 - .../descriptors/GPUCommandEncoderDescriptor.h | 45 - .../descriptors/GPUComputePassDescriptor.h | 56 - .../GPUComputePassTimestampWrites.h | 58 - .../GPUComputePipelineDescriptor.h | 67 - .../descriptors/GPUDawnTogglesDescriptor.h | 56 - .../api/descriptors/GPUDepthStencilState.h | 103 - .../api/descriptors/GPUDeviceDescriptor.h | 109 - .../GPUExternalTextureBindingLayout.h | 38 - .../GPUExternalTextureDescriptor.h | 90 - .../rnwgpu/api/descriptors/GPUFragmentState.h | 73 - .../api/descriptors/GPUImageCopyBuffer.h | 62 - .../descriptors/GPUImageCopyExternalImage.h | 63 - .../api/descriptors/GPUImageCopyTexture.h | 65 - .../descriptors/GPUImageCopyTextureTagged.h | 81 - .../api/descriptors/GPUImageDataLayout.h | 54 - .../cpp/rnwgpu/api/descriptors/GPUMapMode.h | 22 - .../api/descriptors/GPUMultisampleState.h | 54 - .../descriptors/GPUPipelineLayoutDescriptor.h | 57 - .../api/descriptors/GPUPrimitiveState.h | 69 - .../api/descriptors/GPUProgrammableStage.h | 61 - .../api/descriptors/GPUQuerySetDescriptor.h | 55 - .../api/descriptors/GPUQueueDescriptor.h | 43 - .../descriptors/GPURenderBundleDescriptor.h | 45 - .../GPURenderBundleEncoderDescriptor.h | 80 - .../GPURenderPassColorAttachment.h | 81 - .../GPURenderPassDepthStencilAttachment.h | 101 - .../api/descriptors/GPURenderPassDescriptor.h | 92 - .../GPURenderPassTimestampWrites.h | 58 - .../descriptors/GPURenderPipelineDescriptor.h | 103 - .../descriptors/GPURequestAdapterOptions.h | 51 - .../api/descriptors/GPUSamplerBindingLayout.h | 45 - .../api/descriptors/GPUSamplerDescriptor.h | 110 - .../GPUShaderModuleCompilationHint.h | 60 - .../descriptors/GPUShaderModuleDescriptor.h | 62 - .../rnwgpu/api/descriptors/GPUShaderStage.h | 25 - .../descriptors/GPUSharedFenceDescriptor.h | 58 - .../api/descriptors/GPUSharedFenceState.h | 51 - .../GPUSharedTextureMemoryDescriptor.h | 73 - .../api/descriptors/GPUStencilFaceState.h | 64 - .../GPUStorageTextureBindingLayout.h | 59 - .../api/descriptors/GPUTextureBindingLayout.h | 59 - .../api/descriptors/GPUTextureDescriptor.h | 91 - .../rnwgpu/api/descriptors/GPUTextureUsage.h | 29 - .../descriptors/GPUTextureViewDescriptor.h | 91 - .../descriptors/GPUUncapturedErrorEventInit.h | 64 - .../api/descriptors/GPUVertexAttribute.h | 53 - .../api/descriptors/GPUVertexBufferLayout.h | 62 - .../rnwgpu/api/descriptors/GPUVertexState.h | 73 - .../skia/cpp/rnwgpu/api/descriptors/Unions.h | 1969 ----------------- .../skia/cpp/rnwgpu/async/AsyncTaskHandle.cpp | 213 -- .../skia/cpp/rnwgpu/async/AsyncTaskHandle.h | 58 - .../skia/cpp/rnwgpu/async/RuntimeContext.cpp | 199 -- .../skia/cpp/rnwgpu/async/RuntimeContext.h | 134 -- packages/skia/package.json | 3 +- packages/skia/react-native-skia.podspec | 42 +- .../skia/scripts/install-skia-graphite.ts | 99 +- packages/skia/src/mock/__tests__/mock.spec.ts | 1 - packages/skia/src/mock/index.ts | 1 - .../__tests__/e2e/ArrayBuffer.spec.tsx | 79 - .../__tests__/e2e/ArrayBufferBounds.spec.tsx | 213 -- .../__tests__/e2e/ComputeShader.spec.tsx | 274 --- .../__tests__/e2e/DawnToggles.spec.tsx | 111 - .../__tests__/e2e/ErrorScope.spec.tsx | 89 - .../__tests__/e2e/ExternalTexture.spec.tsx | 234 -- .../__tests__/e2e/ImageBitmapBounds.spec.tsx | 94 - .../e2e/ImportExternalTexture.spec.tsx | 325 --- .../e2e/SharedTextureMemory.spec.tsx | 305 --- .../__tests__/e2e/TextureInterop.spec.tsx | 86 + .../skia/src/renderer/__tests__/setup.tsx | 12 +- .../skia/src/skia/types/Image/ImageFactory.ts | 21 +- packages/skia/src/skia/types/Skia.ts | 20 +- packages/skia/src/skia/types/WebGPU.ts | 226 -- packages/skia/src/skia/types/index.ts | 1 - .../skia/src/skia/web/JsiSkImageFactory.ts | 6 +- packages/skia/src/skia/web/JsiSkia.ts | 7 +- .../src/specs/WebGPUViewNativeComponent.ts | 11 - .../specs/WebGPUViewNativeComponent.web.ts | 110 - packages/skia/src/specs/utils.ts | 4 - packages/skia/src/views/WebGPUCanvas.tsx | 125 -- packages/skia/src/views/WebGPUCanvas.web.tsx | 36 - packages/skia/src/views/index.ts | 1 - yarn.lock | 18 + 205 files changed, 724 insertions(+), 17451 deletions(-) create mode 100644 apps/example/src/Examples/WebGPU/PendingInterop.tsx delete mode 100644 packages/skia/android/cpp/jni/JniWebGPUView.cpp delete mode 100644 packages/skia/android/cpp/rnskia-android/SkiaPlatformContext.h delete mode 100644 packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUSurfaceView.java delete mode 100644 packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUTextureView.java delete mode 100644 packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUView.java delete mode 100644 packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewAPI.java delete mode 100644 packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewManager.java delete mode 100644 packages/skia/apple/RNWebGPUAppleNativeBuffer.mm delete mode 100644 packages/skia/apple/SkiaPlatformContext.h delete mode 100644 packages/skia/apple/SkiaPlatformContext.mm delete mode 100644 packages/skia/apple/SkiaWebGPUView.mm delete mode 100644 packages/skia/apple/WebGPUMetalView.mm create mode 100644 packages/skia/cpp/rnskia/RNDawnInterop.cpp delete mode 100644 packages/skia/cpp/rnwgpu/ArrayBuffer.h delete mode 100644 packages/skia/cpp/rnwgpu/Canvas.h delete mode 100644 packages/skia/cpp/rnwgpu/PlatformContext.h delete mode 100644 packages/skia/cpp/rnwgpu/SurfaceRegistry.h delete mode 100644 packages/skia/cpp/rnwgpu/api/AppleNativeBuffer.h delete mode 100644 packages/skia/cpp/rnwgpu/api/Convertors.h delete mode 100644 packages/skia/cpp/rnwgpu/api/External.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPU.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPU.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUAdapter.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUAdapter.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUAdapterInfo.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUBindGroup.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUBindGroup.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUBindGroupLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUBuffer.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUBuffer.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCanvasContext.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCanvasContext.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCommandBuffer.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCompilationInfo.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUCompilationMessage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUComputePipeline.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUComputePipeline.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUDevice.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUDevice.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUError.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUExtent3D.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUExternalTexture.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUExternalTexture.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUFeatures.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUInternalError.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUOrigin2D.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUOrigin3D.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUOutOfMemoryError.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUPipelineLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUQuerySet.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUQuerySet.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUQueue.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUQueue.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderBundle.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderPipeline.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPURenderPipeline.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSampler.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUShaderModule.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUShaderModule.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSharedFence.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSharedFence.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUTexture.cpp delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUTexture.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUTextureView.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h delete mode 100644 packages/skia/cpp/rnwgpu/api/GPUValidationError.h delete mode 100644 packages/skia/cpp/rnwgpu/api/ImageBitmap.h delete mode 100644 packages/skia/cpp/rnwgpu/api/NativeBufferUtils.h delete mode 100644 packages/skia/cpp/rnwgpu/api/RNWebGPU.h delete mode 100644 packages/skia/cpp/rnwgpu/api/WebGPUConstants.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUColor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUColorWrite.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandBufferDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandEncoderDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUFragmentState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUMapMode.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUQueueDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderStage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexState.h delete mode 100644 packages/skia/cpp/rnwgpu/api/descriptors/Unions.h delete mode 100644 packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.cpp delete mode 100644 packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.h delete mode 100644 packages/skia/cpp/rnwgpu/async/RuntimeContext.cpp delete mode 100644 packages/skia/cpp/rnwgpu/async/RuntimeContext.h delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ArrayBuffer.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ArrayBufferBounds.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ComputeShader.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/DawnToggles.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ErrorScope.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ExternalTexture.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ImageBitmapBounds.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/ImportExternalTexture.spec.tsx delete mode 100644 packages/skia/src/renderer/__tests__/e2e/SharedTextureMemory.spec.tsx create mode 100644 packages/skia/src/renderer/__tests__/e2e/TextureInterop.spec.tsx delete mode 100644 packages/skia/src/skia/types/WebGPU.ts delete mode 100644 packages/skia/src/specs/WebGPUViewNativeComponent.ts delete mode 100644 packages/skia/src/specs/WebGPUViewNativeComponent.web.ts delete mode 100644 packages/skia/src/specs/utils.ts delete mode 100644 packages/skia/src/views/WebGPUCanvas.tsx delete mode 100644 packages/skia/src/views/WebGPUCanvas.web.tsx diff --git a/apps/docs/docs/getting-started/installation.md b/apps/docs/docs/getting-started/installation.md index 75a3f81aa1..72453b04a8 100644 --- a/apps/docs/docs/getting-started/installation.md +++ b/apps/docs/docs/getting-started/installation.md @@ -124,7 +124,7 @@ The `jestEnv.js` will load CanvasKit for you and `jestEnv.js` mocks React Native You can also have a look at the [example app](https://github.com/Shopify/react-native-skia/tree/main/apps/example) to see how Jest tests are enabled there. -## Graphite (Experimental) +## Graphite Skia has two backends: Ganesh (default) and Graphite. An experimental preview of Graphite is available in the `@next` distribution channel: @@ -132,11 +132,27 @@ Skia has two backends: Ganesh (default) and Graphite. An experimental preview of yarn add @shopify/react-native-skia@next ``` -:::warning +Skia Graphite requires Android API Level 26 or above. -Graphite support is highly experimental. Skia Graphite requires Android API Level 26 or above. +Graphite runs on [Dawn](https://dawn.googlesource.com/dawn), Google's WebGPU implementation. This is an internal implementation detail: React Native Skia does not expose a WebGPU API itself. To use WebGPU in your app, install [react-native-webgpu](https://github.com/wcandillon/react-native-webgpu) alongside it. -::: +When both packages are installed, they share a single Dawn instance, which enables zero-copy interop between Skia and WebGPU on the shared device: + +```tsx +import { Skia } from "@shopify/react-native-skia"; +import { importDevice, adoptTexture } from "react-native-webgpu"; + +// A WebGPU device backed by Skia's Graphite device +const device = importDevice(Skia.getNativeDevice()); + +// Use an SkImage as a WebGPU texture +const texture = adoptTexture(Skia.Image.MakeNativeTextureFromImage(image)); + +// Use a WebGPU texture as an SkImage +const skImage = Skia.Image.MakeImageFromNativeTexture(texture.nativePointer); +``` + +Both packages must link the exact same Dawn build so that only one copy of Dawn exists in the app — the native build verifies this and fails with a version-mismatch error if the two packages were built against different Dawn releases. If you see that error, align the `@shopify/react-native-skia` and `react-native-webgpu` versions. ## Playground diff --git a/apps/example/ios/Podfile b/apps/example/ios/Podfile index 80473dfa75..90342bddb4 100644 --- a/apps/example/ios/Podfile +++ b/apps/example/ios/Podfile @@ -23,6 +23,22 @@ fix_fmt_consteval = ->(installer) do end end +# react-native-skia and react-native-webgpu both ship a copy of the shared +# JSI infrastructure at identical relative paths (e.g. jsi/NativeObject.h). +# Xcode's all-target headermap would let one pod's include resolve into the +# other pod's file, so disable headermaps for both; each then resolves +# includes only through its own HEADER_SEARCH_PATHS. +example_post_install = ->(installer) do + fix_fmt_consteval.call(installer) + installer.pods_project.targets.each do |target| + next unless ['react-native-skia', 'react-native-webgpu'].include?(target.name) + + target.build_configurations.each do |config| + config.build_settings['USE_HEADERMAP'] = 'NO' + end + end +end + use_test_app! :hermes_enabled => true, :new_arch_enabled => true, - :post_install => fix_fmt_consteval + :post_install => example_post_install diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 79b8fb4a8f..bb216bdf52 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -2009,6 +2009,34 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga + - react-native-webgpu (0.7.1): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - React-NativeModulesApple (0.83.1): - boost - DoubleConversion @@ -2975,6 +3003,7 @@ DEPENDENCIES: - React-microtasksnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) - "react-native-skia (from `../../../node_modules/@shopify/react-native-skia`)" + - react-native-webgpu (from `../../../node_modules/react-native-webgpu`) - React-NativeModulesApple (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-networking (from `../../../node_modules/react-native/ReactCommon/react/networking`) - React-oscompat (from `../../../node_modules/react-native/ReactCommon/oscompat`) @@ -3115,6 +3144,8 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native-safe-area-context" react-native-skia: :path: "../../../node_modules/@shopify/react-native-skia" + react-native-webgpu: + :path: "../../../node_modules/react-native-webgpu" React-NativeModulesApple: :path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-networking: @@ -3208,88 +3239,89 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: ad676c360175e5b8af471b8ce1389e6cf4f9e1ee - RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f + RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 RCTDeprecation: a41bbdd9af30bf2e5715796b313e44ec43eefff1 RCTRequired: 7be34aabb0b77c3cefe644528df0fa0afad4e4d0 RCTSwiftUI: a6c7271c39098bf00dbdad8f8ed997a59bbfbe44 - RCTSwiftUIWrapper: 5ec163e8fde163d3fba714a992b50a266e1ece37 + RCTSwiftUIWrapper: ff9098ccf7727e58218f2f8ea110349863f43438 RCTTypeSafety: 27927d0ca04e419ed9467578b3e6297e37210b5c React: 4bc1f928568ad4bcfd147260f907b4ea5873a03b React-callinvoker: 87f8728235a0dc62e9dc19b3851c829d9347d015 - React-Core: 19e0183e28d7a6613ecacebd7525fe6650efa3b6 - React-CoreModules: 73cc86f2a0ff84b93d6325073ad2e4874d21ad40 - React-cxxreact: 4bf734645c77c9b86e2f3e933e0411cf2f14d1ba + React-Core: 76bed73b02821e5630e7f2cb2e82432ee964695d + React-CoreModules: 752dbfdaeb096658aa0adc4a03ba6214815a08df + React-cxxreact: b6798528aa601c6db66e6adc7e2da2b059c8be74 React-debug: 8978deb306f6f38c28b5091e52b0ac9f942b157e - React-defaultsnativemodule: 724eb9ec388d494f1e2057d83355ee8fe6f1d780 - React-domnativemodule: 9068f41092f725acd09950233d2847364c731947 - React-Fabric: 945cc8abf08d9d0966acef605bffce7b501c49d9 - React-FabricComponents: 4c4ad6f0d16c964a68f945e029505e2eeec6654b - React-FabricImage: a8b628fd98db21b9f8588e06f14a9194dda11b40 - React-featureflags: 0937601c1af1cc125851ec5bbf4654285d47a3e7 - React-featureflagsnativemodule: ac1a3e0353e1a6e15411b17ed6c7122adb0468a4 - React-graphics: cca521e06463608be46207a4aa160f8a7f725f8b - React-hermes: ec50b9fcea2c3bfdd42f8cec845eac3f35888572 - React-idlecallbacksnativemodule: effcae5b7b4473211adb154aaa321d5d9e2fbcc9 - React-ImageManager: b38459e538f1840fa5c3e7612a4bcb0029a3c366 - React-intersectionobservernativemodule: 8d33366661971200cf2e151727f6fe007b62ae7b - React-jserrorhandler: f94c688a0dbe2e045b91b992722b92e97d56f77f - React-jsi: 3216c876cd4c571a57909e22d77c8fd9530aa067 - React-jsiexecutor: 475563c0042841a85930a455d3199f6b1483a5fe - React-jsinspector: bc484fb32bf1b9fed80afe8793e614eba4f7b39e - React-jsinspectorcdp: 5a574d1d35016968a67e78e6b8a7917473ffbb77 - React-jsinspectornetwork: dce3a5a1351b527ee8c28ad4a8bdd211507e1a45 - React-jsinspectortracing: 65f6b166bd67e5adc31eba027e1570bacf7a3cc7 - React-jsitooling: d5463f5489a31640b0fa0ec4e31566ca8aa86c13 - React-jsitracing: 3c7fc18821aba64855acb8658aa857ca6a7fddf6 - React-logger: 6ac901f5c7f7321d2be1a40b203bccc2e23411e3 - React-Mapbuffer: 2e0e7cc5b7064eaed9c8b8afc3a87621cb7ef5cd - React-microtasksnativemodule: dd4d33b251b57e5027c572c6d0b45cbfbcfaa386 - react-native-safe-area-context: 54d812805f3c4e08a4580ad086cbde1d8780c2e4 - react-native-skia: 4a90dfa21f4544d69c6be0c49958378169a88532 - React-NativeModulesApple: 7f2f2fed3f6c858889eb61d09941be965d52df58 - React-networking: 43e5e6773ac2ca2a93261a1388fed269c9fce092 + React-defaultsnativemodule: 682b77ef4acfb298017be15f4f93c1d998deb174 + React-domnativemodule: 4c4b44f7eb68dbc3a2218db088bef318a7302017 + React-Fabric: b6f82a4d8498ce4475586f71ca8397a771fe292d + React-FabricComponents: c8695f4b11918a127c4560d66f7d3fdb01a17986 + React-FabricImage: d64f48830f63830e8ffaaf69fa487116856fbbf1 + React-featureflags: 2a46b229903e906d33dbaf9207ce57c59306c369 + React-featureflagsnativemodule: cba6c0814051a0934f8bcee4a436ee2a6bcc9754 + React-graphics: 3d0435051e1ab8904d065f8ffbe981a9fc202841 + React-hermes: 32fc9c231c1aa5c2fcfe851b0d19ee9269f88f4c + React-idlecallbacksnativemodule: f8ee42581795c4844d97147596bcc2d824c0f188 + React-ImageManager: e8f7377ef0585fd2df05559a17e01a03e187d5cf + React-intersectionobservernativemodule: b1bea12ca29accdd2eda60c87605a6030b894eb9 + React-jserrorhandler: 1a86df895b4eaf4e771abe8cf34cbb26d821f771 + React-jsi: adf8527fec197ad9d0480cc5b8945eb56de627f0 + React-jsiexecutor: 315fa2f879b43e3a9ca08f5f4b733472f7e4e8a4 + React-jsinspector: b4fd1933666bcb2549b566b40656c1e45e9d7632 + React-jsinspectorcdp: 80141710f2668e5b8f00417298d9b76b4abf90fa + React-jsinspectornetwork: 1d3ea717dbbec316cd8c21a0af53928a7bf74901 + React-jsinspectortracing: 4ce745374d4b2bfbd164cce9f8de8383d3d818a0 + React-jsitooling: fc4ac4c3b1f3f9f7fedf0c777c6ff3f244f568bd + React-jsitracing: bff08a6faeef4a9bd286487da191f5e5329e21a9 + React-logger: b8483fa08e0d62e430c76d864309d90576ca2f68 + React-Mapbuffer: 7b72a669e94662359dad4f42b5af005eb24b4e83 + React-microtasksnativemodule: cdc02da075f2857803ed63f24f5f72fc40e094c0 + react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460 + react-native-skia: 398d81d07392758762cf114280cceb24ebc9b6f3 + react-native-webgpu: 763fca525e9f3186e3b12adc237d95c36984f1a7 + React-NativeModulesApple: a2c3d2cbec893956a5b3e4060322db2984fff75b + React-networking: 3f98bd96893a294376e7e03730947a08d474c380 React-oscompat: 80166b66da22e7af7fad94474e9997bd52d4c8c6 - React-perflogger: 63c90e0d8c24df87ffa14dad01aeafc352847dd0 - React-performancecdpmetrics: 5a9b81c08f75045635127d626440d9ada01e774b - React-performancetimeline: 31cebfff69ec9174b3fb54b0606fcb12ef91cbad + React-perflogger: d6797918d2b1031e91a9d8f5e7fdd2c8728fb390 + React-performancecdpmetrics: 5570be61e2f97c4741c5d432c91570e8e5a39892 + React-performancetimeline: 5763499ae1991fc18dcf416e340ce7bc829bb298 React-RCTActionSheet: 3bd5f5db9f983cf38d51bb9a7a198e2ebea94821 - React-RCTAnimation: 346865a809fa5132f6c594c8b376c6cf46b44e88 - React-RCTAppDelegate: b2d1e0d3663c987f49f45094883b9e36fcbf0181 - React-RCTBlob: 74759ebb7ff9077d19f60c301782c1f8c3eb2813 - React-RCTFabric: 7b4b14dad21ca99333ebcbc0bf5c205647a315a8 - React-RCTFBReactNativeSpec: 39151968adb68b8c59f29a8bd4223d4d7780a793 - React-RCTImage: 60763f56e8a5e45d861d7c4777e428bb820ec52a - React-RCTLinking: 52aee78b0b3163167c7fcf58f80a42943c03a056 - React-RCTNetwork: f5e1e8ae5eff6982efff6289b06ec0a76d0a6ac2 - React-RCTRuntime: 0e99199322afd372e74b95ae5c58f4e074cc2855 - React-RCTSettings: 298bb40d3412bf32e0b4f0797e48416b0b7278a1 - React-RCTText: dfb74800e27d792d1188fa975a3b9807c3362e3e - React-RCTVibration: ffe5fd4f50a835e353a3b6869eb005dab11eea44 + React-RCTAnimation: 46a9978f27dc434dbeed16afa7b82619b690a9af + React-RCTAppDelegate: 62ecd60a2b2a8cae26ce6a066bfa59cfde97af01 + React-RCTBlob: 8285c859513023ee3cc8c806d9b59d4da078c4ba + React-RCTFabric: 05ed09347e938de985052f791a6a0698816d5761 + React-RCTFBReactNativeSpec: 83ba579fca9a51e774ac32578ef5dd3262edd7e2 + React-RCTImage: a5364d0f098692cfbf5bef1e8a63e7712ecb14b7 + React-RCTLinking: 34b63b0aa0e92d30f5d7aa2c255a8f95fa75ee8f + React-RCTNetwork: 1ef88b7a5310b8f915d3556b5b247def113191ed + React-RCTRuntime: ed29cf68a46782fec891e5afe1d8d758ca6ccd9b + React-RCTSettings: 2c45623d6c0f30851a123f621eb9d32298bcbb0c + React-RCTText: 0ee70f5dc18004b4d81b2c214267c6cbec058587 + React-RCTVibration: 88557e21e7cc3fe76b5b174cba28ff45c6def997 React-rendererconsistency: d280314a3e7f0097152f89e815b4de821c2be8b9 - React-renderercss: 8a1a346f3665fd5ea7a7be7b3b9f95d4743e1180 - React-rendererdebug: af74afdfb3d6c5382ebab35562efd8eb9e690473 - React-RuntimeApple: 06e33d291e72fd0c73ac47046c3536d77d5aeedd - React-RuntimeCore: 99273d2af072062eb07f0b2d2d4a0f2de697ea14 - React-runtimeexecutor: 2063c03c18810ee57939d138142e6493333360ef - React-RuntimeHermes: 2253a7f4c8d56b449230b330b0b15383ed4b3df4 - React-runtimescheduler: ff37ac6720a943da91645c06274282ac46b71f23 - React-timing: 831d7e081ba4c332ca5cccf389b88e363f13f2b4 - React-utils: 25db6c17598c4fed22b5956d7551bb8bddf1f95b - React-webperformancenativemodule: 57e41e6193cfb815bde0b5534bef68673f1270eb - ReactAppDependencyProvider: bfb12ead469222b022a2024f32aba47ce50de512 - ReactCodegen: 9ca1bd49eee1eccf6e427e406d2163f49e9c48c0 - ReactCommon: 05ad684db7d88e194272ae26baddf6300e30b8b7 - ReactNativeHost: e7e0a518b0120f0070b3e1f13c7006d3e0e8ee13 - ReactTestApp-DevSupport: 6994b53b5b81139a8ce63e0776c726c95de079a1 + React-renderercss: f8cbf83d95c2c2bbf893d37fe50c73f046584411 + React-rendererdebug: 37216ddfcd38e49d1e92bf9052ea4bc9d7b932e5 + React-RuntimeApple: 1c0e7cb8e1c2c5775585afcaaa666ec151629a8d + React-RuntimeCore: 925fe2ca24cf8e6ed87586dbb92827306b93b83f + React-runtimeexecutor: 962dae024f6df760d029512a7d99e3f73d570935 + React-RuntimeHermes: 19a7c59ec1bc9908516f0bbc29b49425f6ec64ba + React-runtimescheduler: 62f21127cd97f4d8f164eee5150d3ce53dd36f66 + React-timing: 8757bf6fb96227c264f2d1609f4ba5c68217b8ce + React-utils: 8ab26781c2f5c2f7fafb2022c8ab39d39f231b80 + React-webperformancenativemodule: 7953b7fe519f76fa595111fe18ff3d5de131bfe9 + ReactAppDependencyProvider: 0eb286cc274abb059ee601b862ebddac2e681d01 + ReactCodegen: b8e56b780fffe6edd6405be0af4a1e3049a937f7 + ReactCommon: ac934cb340aee91282ecd6f273a26d24d4c55cae + ReactNativeHost: eef98ec49b55d88ad4cabf5a4378a12b42b551ee + ReactTestApp-DevSupport: ea18f446cff64b6c9a3e28788600c82ecf51bde6 ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf - RNGestureHandler: 77eecab5fd636666ca73a55bb61e2f1a685b7e84 - RNReanimated: d1a7a4c20eefc371e062990ce1debeaff4f1b9be - RNScreens: b2a5c76af24a02a2fd71bfce42780fdd9c79cc6d - RNSVG: ea9cbf6dcdbebdfff5822b0ad9311bbc4510a0b7 - RNWorklets: 5f6e5664c1819eac103ca75cc2f36191f55aa110 + RNGestureHandler: cd4be101cfa17ea6bbd438710caa02e286a84381 + RNReanimated: c26dfcd831add485c2ed93de9d7bfb90b035eeaa + RNScreens: 714e10b6b554f7dc7ad9f78dcf36dc8e3fc73415 + RNSVG: 11354d28dd6cb71a59570b68c91ba6772a2d781d + RNWorklets: b89b501d37972e6419d6f87effe41d6d76157648 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: 5bd0956bf9cb16f75101e78b5e852c7577bc5a45 + Yoga: 5456bb010373068fc92221140921b09d126b116e -PODFILE CHECKSUM: dca89d921c9f2a2d3d405a5fca0bfb60b30b5022 +PODFILE CHECKSUM: 7b64fbddf0a0f7c0c19eaa9ca71bc7cdf4e2c959 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/apps/example/jest.config.mjs b/apps/example/jest.config.mjs index 1f336e0454..426c88d97c 100644 --- a/apps/example/jest.config.mjs +++ b/apps/example/jest.config.mjs @@ -10,6 +10,7 @@ const config = { testEnvironment: "@shopify/react-native-skia/jestEnv.js", setupFilesAfterEnv: [ "@shopify/react-native-skia/jestSetup.js", + "react-native-webgpu/jestSetup.js", "/../../node_modules/react-native-gesture-handler/jestSetup.js", "/jestSetup.js", ], diff --git a/apps/example/macos/Podfile b/apps/example/macos/Podfile index 39bfb76d59..c57dc69ae8 100644 --- a/apps/example/macos/Podfile +++ b/apps/example/macos/Podfile @@ -8,4 +8,17 @@ workspace 'example.xcworkspace' platform :osx, '14.0' -use_test_app! :hermes_enabled => true, :new_arch_enabled => true +use_test_app!(:hermes_enabled => true, :new_arch_enabled => true) do + # react-native-webgpu doesn't support macOS yet. Its podspec still declares + # `:osx` support, so plain autolinking (which only looks at the podspec, not + # react-native.config.js platform overrides) would otherwise pull it in here. + # AutolinkingUtils is defined by this point (use_react_native! ran above), + # and use_native_modules! (which reads it) hasn't run yet. + AutolinkingUtils.singleton_class.prepend(Module.new do + def is_platform_supported?(current_target_definition, spec) + return false if spec.name == 'react-native-webgpu' + + super + end + end) +end diff --git a/apps/example/macos/Podfile.lock b/apps/example/macos/Podfile.lock index 4474f2db74..c609d6296f 100644 --- a/apps/example/macos/Podfile.lock +++ b/apps/example/macos/Podfile.lock @@ -2967,7 +2967,7 @@ SPEC CHECKSUMS: React-Mapbuffer: 0762646502d342de6233944f5fc5de693f8dc5fe React-microtasksnativemodule: a68f10fd392c22077dcdb0fddf14a0821671568f react-native-safe-area-context: 54d812805f3c4e08a4580ad086cbde1d8780c2e4 - react-native-skia: 2c1a5775d1fdf527cfd7ec08bab9c390f5ea7cbe + react-native-skia: 765e9975e9ccde5ce3c9a0f740f195108c7d0280 React-NativeModulesApple: fa28524f6e6713ad2ab3db1551880cf75124d66b React-oscompat: 0f67bb3326c613877d9a4c50031f215fe2764d89 React-perflogger: 63c8c850e4218aa1efccb98ea41639b5d1c8af7c @@ -3008,6 +3008,6 @@ SPEC CHECKSUMS: SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: f8fbb5ed063104fccbb72600ec9f3d7269a73afa -PODFILE CHECKSUM: 84e2ebec97f39c90cf0ff66e5b5d9147701879ef +PODFILE CHECKSUM: 35f3376a4c1b55f393bedb6092b65e22eba190c3 COCOAPODS: 1.15.2 diff --git a/apps/example/package.json b/apps/example/package.json index 6709fbc0a8..bc2005a973 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -40,6 +40,7 @@ "react-native-screens": "^4.10.0", "react-native-svg": "patch:react-native-svg@npm%3A15.14.0#../../.yarn/patches/react-native-svg-npm-15.14.0-macos-uiimage-fix.patch", "react-native-web": "^0.21.2", + "react-native-webgpu": "0.8.0", "react-native-windows": "^0.75.0", "react-native-worklets": "0.8.3" }, diff --git a/apps/example/src/Examples/WebGPU/ImportExternalTexture.tsx b/apps/example/src/Examples/WebGPU/ImportExternalTexture.tsx index 02d72404f7..e70e0420dd 100644 --- a/apps/example/src/Examples/WebGPU/ImportExternalTexture.tsx +++ b/apps/example/src/Examples/WebGPU/ImportExternalTexture.tsx @@ -1,7 +1,9 @@ import React, { useEffect, useRef } from "react"; -import { StyleSheet, View, Text } from "react-native"; -import type { WebGPUCanvasRef, NativeBuffer } from "@shopify/react-native-skia"; -import { WebGPUCanvas, Skia } from "@shopify/react-native-skia"; +import { StyleSheet, View } from "react-native"; +import type { NativeBuffer } from "@shopify/react-native-skia"; +import { Skia } from "@shopify/react-native-skia"; +import type { CanvasRef } from "react-native-webgpu"; +import { Canvas, importDevice } from "react-native-webgpu"; // Demonstrates GPUDevice.importExternalTexture with a self-contained source: a // platform native buffer (CVPixelBufferRef on iOS, AHardwareBuffer on Android) @@ -54,7 +56,7 @@ fn fs_main(in: VsOut) -> @location(0) vec4f { `; export function ImportExternalTexture() { - const canvasRef = useRef(null); + const canvasRef = useRef(null); const animationRef = useRef(0); const cleanupRef = useRef<(() => void) | null>(null); @@ -62,7 +64,7 @@ export function ImportExternalTexture() { let cancelled = false; const init = () => { - if (!canvasRef.current || typeof RNWebGPU === "undefined") { + if (!canvasRef.current) { return; } const ctx = canvasRef.current.getContext("webgpu"); @@ -70,7 +72,7 @@ export function ImportExternalTexture() { return; } - const device = Skia.getDevice(); + const device = importDevice(Skia.getNativeDevice()); const canvas = ctx.canvas as unknown as { width: number; height: number }; const format = navigator.gpu.getPreferredCanvasFormat(); ctx.configure({ device, format, alphaMode: "premultiplied" }); @@ -108,6 +110,11 @@ export function ImportExternalTexture() { TEXTURE_SIZE, TEXTURE_SIZE ); + // Wrap the platform buffer (CVPixelBuffer / AHardwareBuffer pointer) in + // a react-native-webgpu VideoFrame so it can feed importExternalTexture. + const videoFrame = RNWebGPU.createVideoFrameFromNativeBuffer( + nativeBuffer as bigint + ); let uniformsWritten = false; const render = () => { @@ -141,7 +148,7 @@ export function ImportExternalTexture() { let externalTexture: GPUExternalTexture | null = null; try { externalTexture = device.importExternalTexture({ - source: nativeBuffer, + source: videoFrame as unknown as VideoFrame, label: "test-pattern", }); } catch (e) { @@ -185,24 +192,9 @@ export function ImportExternalTexture() { }; }, []); - if (typeof RNWebGPU === "undefined") { - return ( - - - - External textures require SK_GRAPHITE to be enabled. - - - Build react-native-skia with Graphite support to use this feature. - - - - ); - } - return ( - + ); } diff --git a/apps/example/src/Examples/WebGPU/PendingInterop.tsx b/apps/example/src/Examples/WebGPU/PendingInterop.tsx new file mode 100644 index 0000000000..6a6ed1796d --- /dev/null +++ b/apps/example/src/Examples/WebGPU/PendingInterop.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import { StyleSheet, Text, View } from "react-native"; + +// The WebGPU API surface moved from @shopify/react-native-skia to +// react-native-webgpu. The zero-copy Skia <-> WebGPU texture interop +// (Skia.Image.MakeTextureFromImage / MakeImageFromTexture on a shared device) +// is being rebuilt on top of the cross-package interop API and these demos +// will come back with it. The previous implementations live in git history. +export const PendingInterop = ({ name }: { name: string }) => ( + + + {name} is temporarily unavailable. + + This demo relies on the Skia/WebGPU texture interop, which is being + migrated to the react-native-webgpu interop API. + + + +); + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#1a1a1a", + }, + messageContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + padding: 20, + }, + message: { + color: "#fff", + fontSize: 18, + textAlign: "center", + marginBottom: 10, + }, + submessage: { + color: "#888", + fontSize: 14, + textAlign: "center", + }, +}); diff --git a/apps/example/src/Examples/WebGPU/TexturedCube.tsx b/apps/example/src/Examples/WebGPU/TexturedCube.tsx index dd7b170f5e..01e48035cb 100644 --- a/apps/example/src/Examples/WebGPU/TexturedCube.tsx +++ b/apps/example/src/Examples/WebGPU/TexturedCube.tsx @@ -1,13 +1,13 @@ import React, { useEffect, useRef } from "react"; -import { StyleSheet, View, Text } from "react-native"; +import { StyleSheet, View } from "react-native"; import type { SkCanvas, SkParagraph, SkTextStyle, - WebGPUCanvasRef, } from "@shopify/react-native-skia"; +import type { CanvasRef } from "react-native-webgpu"; +import { adoptTexture, Canvas, importDevice } from "react-native-webgpu"; import { - WebGPUCanvas, Skia, BlurStyle, BlendMode, @@ -159,7 +159,7 @@ function drawTexture3(canvas: SkCanvas, t: number) { } export function TexturedCube() { - const canvasRef = useRef(null); + const canvasRef = useRef(null); const animationRef = useRef(0); const cleanupRef = useRef<(() => void) | null>(null); const customFontMgr = useFonts(paragraphFonts); @@ -169,9 +169,6 @@ export function TexturedCube() { if (!canvasRef.current) { return; } - if (typeof RNWebGPU === "undefined") { - return; - } if (!customFontMgr) { return; } @@ -180,7 +177,7 @@ export function TexturedCube() { return; } - const device = Skia.getDevice(); + const device = importDevice(Skia.getNativeDevice()); const canvas = ctx.canvas as HTMLCanvasElement; const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); @@ -391,27 +388,29 @@ export function TexturedCube() { // Update Skia textures drawTexture1(surface1.getCanvas(), t); surface1.flush(); - const tex1 = Skia.Image.MakeTextureFromImage( - surface1.makeImageSnapshot() + const tex1 = adoptTexture( + Skia.Image.MakeNativeTextureFromImage(surface1.makeImageSnapshot()) ); const bindGroup1 = createBindGroup(tex1); drawTexture2(surface2.getCanvas(), t, paragraph); surface2.flush(); - const tex2 = Skia.Image.MakeTextureFromImage( - surface2.makeImageSnapshot() + const tex2 = adoptTexture( + Skia.Image.MakeNativeTextureFromImage(surface2.makeImageSnapshot()) ); const bindGroup2 = createBindGroup(tex2); drawTexture3(surface3.getCanvas(), t); surface3.flush(); - const tex3 = Skia.Image.MakeTextureFromImage( - surface3.makeImageSnapshot() + const tex3 = adoptTexture( + Skia.Image.MakeNativeTextureFromImage(surface3.makeImageSnapshot()) ); const bindGroup3 = createBindGroup(tex3); const frame = video.nextImage(); - const tex4 = frame ? Skia.Image.MakeTextureFromImage(frame) : null; + const tex4 = frame + ? adoptTexture(Skia.Image.MakeNativeTextureFromImage(frame)) + : null; const bindGroup4 = tex4 ? createBindGroup(tex4) : null; // Update MVP matrix @@ -453,6 +452,15 @@ export function TexturedCube() { device.queue.submit([commandEncoder.finish()]); ctx.present(); + // These textures are recreated every frame; destroy them eagerly + // instead of waiting for GC so VRAM stays bounded. destroy() after + // submit is safe: already-submitted work keeps the texture alive + // until it completes. + tex1.destroy(); + tex2.destroy(); + tex3.destroy(); + tex4?.destroy(); + animationRef.current = requestAnimationFrame(render); }; @@ -471,24 +479,9 @@ export function TexturedCube() { }; }, [customFontMgr]); - if (typeof RNWebGPU === "undefined") { - return ( - - - - WebGPU Canvas requires SK_GRAPHITE to be enabled. - - - Build react-native-skia with Graphite support to use this feature. - - - - ); - } - return ( - + ); } diff --git a/apps/example/src/Examples/WebGPU/Triangle.tsx b/apps/example/src/Examples/WebGPU/Triangle.tsx index 5e5ff04eba..c01d052c1a 100644 --- a/apps/example/src/Examples/WebGPU/Triangle.tsx +++ b/apps/example/src/Examples/WebGPU/Triangle.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef } from "react"; -import { StyleSheet, View, Text } from "react-native"; -import type { WebGPUCanvasRef } from "@shopify/react-native-skia"; -import { WebGPUCanvas } from "@shopify/react-native-skia"; +import { StyleSheet, View } from "react-native"; +import type { CanvasRef } from "react-native-webgpu"; +import { Canvas, importDevice } from "react-native-webgpu"; +import { Skia } from "@shopify/react-native-skia"; const triangleShader = ` @vertex @@ -21,54 +22,52 @@ fn fs_main() -> @location(0) vec4f { `; export function Triangle() { - const canvasRef = useRef(null); - const animationRef = useRef(0); - const cleanupRef = useRef<(() => void) | null>(null); + const ref = useRef(null); useEffect(() => { - // Small delay to ensure the canvas is mounted - const timeoutId = setTimeout(async () => { - if (!canvasRef.current) { - return; - } - - // Check if RNWebGPU is available (SK_GRAPHITE must be enabled) - if (typeof RNWebGPU === "undefined") { - console.warn( - "RNWebGPU is not available. Make sure SK_GRAPHITE is enabled." + let running = true; + let frame = 0; + + (async () => { + // Shared-device interop: adopt Skia's Graphite device so WebGPU work and + // Skia rendering share one wgpu::Device (zero-copy handoff becomes + // possible). Falls back to a standalone device when unavailable. + let device: GPUDevice; + try { + device = importDevice(Skia.getNativeDevice()); + console.log( + "[webgpu-coexistence] rendering with Skia's Graphite device" ); - return; + } catch (e) { + console.log( + "[webgpu-coexistence] falling back to a standalone device", + e + ); + const adapter = await navigator.gpu.requestAdapter(); + if (!adapter) { + console.warn("Failed to get GPU adapter"); + return; + } + device = await adapter.requestDevice(); } - const ctx = canvasRef.current.getContext("webgpu"); - if (!ctx) { + const context = ref.current?.getContext("webgpu"); + if (!context) { console.warn("Failed to get WebGPU context"); return; } - // Get the device from navigator.gpu - const adapter = await navigator.gpu.requestAdapter(); - if (!adapter) { - console.warn("Failed to get GPU adapter"); - return; - } - - const device = await adapter.requestDevice(); - - // Configure the context const format = navigator.gpu.getPreferredCanvasFormat(); - ctx.configure({ + context.configure({ device, format, alphaMode: "opaque", }); - // Create shader module const shaderModule = device.createShaderModule({ code: triangleShader, }); - // Create render pipeline const pipeline = device.createRenderPipeline({ layout: "auto", vertex: { @@ -85,14 +84,14 @@ export function Triangle() { }, }); - let running = true; + console.log("[webgpu-coexistence] pipeline ready, rendering triangle"); const render = () => { if (!running) { return; } - const texture = ctx.getCurrentTexture(); + const texture = context.getCurrentTexture(); const renderPassDescriptor: GPURenderPassDescriptor = { colorAttachments: [ { @@ -112,44 +111,23 @@ export function Triangle() { passEncoder.end(); device.queue.submit([commandEncoder.finish()]); - ctx.present(); + context.present(); - animationRef.current = requestAnimationFrame(render); + frame = requestAnimationFrame(render); }; - animationRef.current = requestAnimationFrame(render); - - cleanupRef.current = () => { - running = false; - cancelAnimationFrame(animationRef.current); - }; - }, 100); + frame = requestAnimationFrame(render); + })(); return () => { - clearTimeout(timeoutId); - cleanupRef.current?.(); + running = false; + cancelAnimationFrame(frame); }; }, []); - // Check if WebGPU is available - if (typeof RNWebGPU === "undefined") { - return ( - - - - WebGPU Canvas requires SK_GRAPHITE to be enabled. - - - Build react-native-skia with Graphite support to use this feature. - - - - ); - } - return ( - + ); } @@ -162,21 +140,4 @@ const styles = StyleSheet.create({ canvas: { flex: 1, }, - messageContainer: { - flex: 1, - justifyContent: "center", - alignItems: "center", - padding: 20, - }, - message: { - color: "#fff", - fontSize: 18, - textAlign: "center", - marginBottom: 10, - }, - submessage: { - color: "#888", - fontSize: 14, - textAlign: "center", - }, }); diff --git a/apps/example/src/Examples/WebGPU/Wireframes.tsx b/apps/example/src/Examples/WebGPU/Wireframes.tsx index b3fcee2f51..81ce1e0f98 100644 --- a/apps/example/src/Examples/WebGPU/Wireframes.tsx +++ b/apps/example/src/Examples/WebGPU/Wireframes.tsx @@ -20,6 +20,7 @@ import { View, } from "react-native"; import { useDerivedValue } from "react-native-reanimated"; +import { importDevice } from "react-native-webgpu"; import { useLoop } from "../../components/Animations"; @@ -163,7 +164,7 @@ export function Wireframes() { //rect(0, 0, 300, (300 * bounds.height) / bounds.width); useEffect(() => { - const device = Skia.getDevice(); + const device = importDevice(Skia.getNativeDevice()); const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); const depthFormat = "depth24plus"; @@ -498,7 +499,7 @@ export function Wireframes() { device.queue.submit([commandBuffer]); // Convert texture to SkImage - const skImage = Skia.Image.MakeImageFromTexture(texture); + const skImage = Skia.Image.MakeImageFromNativeTexture(texture.nativePointer); setImage(skImage); }; diff --git a/apps/example/src/Home/HomeScreen.tsx b/apps/example/src/Home/HomeScreen.tsx index a9e7023523..a73b65d5b3 100644 --- a/apps/example/src/Home/HomeScreen.tsx +++ b/apps/example/src/Home/HomeScreen.tsx @@ -1,12 +1,16 @@ -import { Skia } from "@shopify/react-native-skia"; import React from "react"; import { ScrollView } from "react-native"; +// Side-effect import: installs navigator.gpu. Required here because Metro's +// inlineRequires defers module evaluation to first binding use, so without it +// react-native-webgpu would not be initialized when the WebGPU section's +// availability check below runs. +import "react-native-webgpu"; import { HomeScreenButton } from "./HomeScreenButton"; -const hasWebGPU = Skia.hasDevice(); - export const HomeScreen = () => { + const hasWebGPU = + typeof navigator !== "undefined" && navigator.gpu != null; return ( { try { - return Skia.hasDevice?.() ?? false; + return typeof Skia.getNativeDevice() === "bigint"; } catch { return false; } diff --git a/externals/skia b/externals/skia index 9f330f1704..a7fb0b3c2e 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 9f330f1704305686dafa9eeef11de77caa5314b1 +Subproject commit a7fb0b3c2e109e4e68f50bf823cf6b8d524c4a0c diff --git a/packages/skia/android/CMakeLists.txt b/packages/skia/android/CMakeLists.txt index 1341c12ad8..a9ccfa7312 100644 --- a/packages/skia/android/CMakeLists.txt +++ b/packages/skia/android/CMakeLists.txt @@ -70,6 +70,7 @@ if(SK_GRAPHITE) set(BACKEND_SOURCES #TODO: is this source needed to be added? "${PROJECT_SOURCE_DIR}/../cpp/rnskia/RNDawnWindowContext.cpp" + "${PROJECT_SOURCE_DIR}/../cpp/rnskia/RNDawnInterop.cpp" ) else() add_definitions(-DSK_GL -DSK_GANESH) @@ -114,39 +115,6 @@ add_library( ${BACKEND_SOURCES} ) -if(SK_GRAPHITE) - target_sources(${PACKAGE_NAME} PRIVATE - # WebGPU async system - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/AsyncTaskHandle.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/async/RuntimeContext.cpp" - - # WebGPU API - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPU.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUAdapter.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUBindGroup.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUBuffer.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUCanvasContext.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUCommandEncoder.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUComputePassEncoder.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUComputePipeline.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUDevice.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUDeviceLostInfo.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUExternalTexture.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUQuerySet.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUQueue.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPURenderBundleEncoder.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPURenderPassEncoder.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPURenderPipeline.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUShaderModule.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUSharedFence.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUSharedTextureMemory.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUSupportedLimits.cpp" - "${PROJECT_SOURCE_DIR}/../cpp/rnwgpu/api/GPUTexture.cpp" - - # WebGPU Canvas JNI bindings - "${PROJECT_SOURCE_DIR}/cpp/jni/JniWebGPUView.cpp" - ) -endif() target_include_directories( @@ -176,12 +144,8 @@ target_include_directories( ../cpp/rnskia/values ../cpp/utils - # WebGPU bindings + # Shared JSI infrastructure (cpp/jsi) via prefix-qualified includes ../cpp - ../cpp/rnwgpu - ../cpp/rnwgpu/api - ../cpp/rnwgpu/api/descriptors - ../cpp/rnwgpu/async ${libfbjni_include_DIRS} ) @@ -214,8 +178,10 @@ add_library(jsonreader STATIC IMPORTED) set_property(TARGET jsonreader PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libjsonreader.a") if(SK_GRAPHITE) - add_library(dawn_combined STATIC IMPORTED) - set_property(TARGET dawn_combined PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libdawn_combined.a") + # Dawn is a shared library, the same artifact react-native-webgpu links, so + # an app that installs both packages loads exactly one Dawn copy. + add_library(webgpu_dawn SHARED IMPORTED) + set_property(TARGET webgpu_dawn PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libwebgpu_dawn.so") endif() find_library( @@ -390,7 +356,7 @@ endif() if(SK_GRAPHITE) target_link_libraries(${PACKAGE_NAME} ${COMMON_LIBS} - dawn_combined + webgpu_dawn ) else() target_link_libraries(${PACKAGE_NAME} diff --git a/packages/skia/android/build.gradle b/packages/skia/android/build.gradle index f1eb21a5d6..357647ab0c 100644 --- a/packages/skia/android/build.gradle +++ b/packages/skia/android/build.gradle @@ -88,6 +88,39 @@ def skiaLibsPath = useGraphite : "${resolveNodePackage('react-native-skia-graphite-android', projectDir)}/libs") : "${resolveNodePackage('react-native-skia-android', projectDir)}/libs" +// Both packages must link the exact same Dawn artifact: compare this +// Graphite build's Dawn release tag (libs/.dawn-version) with the tag +// react-native-webgpu declares in its package.json `dawn` field. +if (useGraphite) { + def dawnMarker = file("${projectDir}/../libs/.dawn-version") + def webgpuDir = null + try { + webgpuDir = resolveNodePackage('react-native-webgpu', projectDir) + } catch (Exception ignored) { + // react-native-webgpu not installed: nothing to check + } + if (dawnMarker.exists() && webgpuDir != null) { + def skiaDawn = dawnMarker.text.trim() + def webgpuJson = new groovy.json.JsonSlurper().parse(file("${webgpuDir}/package.json")) + if (webgpuJson.dawn == null) { + throw new GradleException( + "react-native-skia: the installed react-native-webgpu " + + "(${webgpuJson.version}) does not declare a `dawn` field in its " + + "package.json, so it predates shared-Dawn support and cannot be " + + "paired with this Graphite build (which links ${skiaDawn}). " + + "Upgrade react-native-webgpu.") + } + def webgpuDawn = "dawn-" + webgpuJson.dawn.toString().replace('/', '-') + if (skiaDawn != webgpuDawn) { + throw new GradleException( + "react-native-skia: Dawn version mismatch. This Graphite build links " + + "${skiaDawn} but react-native-webgpu links ${webgpuDawn}. " + + "Align the two packages so the app contains exactly one Dawn.") + } + logger.warn("react-native-skia: Dawn versions match (${skiaDawn})") + } +} + logger.warn("react-native-skia: SK_GRAPHITE: ${useGraphite}") logger.warn("react-native-skia: Skia libs: ${skiaLibsPath}") logger.warn("react-native-skia: node_modules/ found at: ${nodeModules}") diff --git a/packages/skia/android/cpp/jni/JniWebGPUView.cpp b/packages/skia/android/cpp/jni/JniWebGPUView.cpp deleted file mode 100644 index 9d94bfbec1..0000000000 --- a/packages/skia/android/cpp/jni/JniWebGPUView.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include - -#ifdef SK_GRAPHITE -#include -#include - -#include - -#include "rnskia/RNDawnContext.h" -#include "rnwgpu/SurfaceRegistry.h" -#include "rnwgpu/async/RuntimeContext.h" -#include "webgpu/webgpu_cpp.h" - -namespace { -// Applies a surface attach latched by the platform UI thread (see -// SurfaceInfo::applyPendingAttach) from the JS thread. Surface attaches are -// normally adopted at the next frame boundary by whichever thread renders; -// this flush covers contexts that are not actively rendering (static -// content), so the last offscreen frame still makes it on screen. Mirrors -// react-native-webgpu's RNWebGPUManager::flushPendingSurfaceTransition. -void flushPendingSurfaceTransition(std::shared_ptr info) { - if (info == nullptr) { - return; - } - auto invoker = rnwgpu::async::RuntimeContext::mainCallInvoker(); - if (invoker == nullptr) { - return; - } - invoker->invokeAsync( - [info = std::move(info)] { info->applyPendingAttach(); }); -} -} // namespace -#endif - -extern "C" JNIEXPORT void JNICALL -Java_com_shopify_reactnative_skia_WebGPUView_onSurfaceCreate( - JNIEnv *env, jobject thiz, jobject jSurface, jint contextId, jfloat width, - jfloat height) { -#ifdef SK_GRAPHITE - // ANativeWindow_fromSurface acquires a reference; SurfaceInfo releases it - // (via the releaser below) once it is done with the window. - auto window = ANativeWindow_fromSurface(env, jSurface); - if (window == nullptr) { - return; - } - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto &dawnContext = RNSkia::DawnContext::getInstance(); - auto gpu = dawnContext.getWGPUInstance(); - - // Create surface from ANativeWindow - wgpu::SurfaceSourceAndroidNativeWindow androidSurfaceDesc; - androidSurfaceDesc.window = window; - wgpu::SurfaceDescriptor surfaceDescriptor; - surfaceDescriptor.nextInChain = &androidSurfaceDesc; - auto surface = gpu.CreateSurface(&surfaceDescriptor); - - // Find-or-create + attach runs atomically under the registry lock so a - // concurrent destroyContext cannot orphan this surface. - auto info = registry.attachSurface( - contextId, gpu, static_cast(width), static_cast(height), window, - surface, [](void *nativeSurface) { - ANativeWindow_release(static_cast(nativeSurface)); - }); - // The attach is adopted at the next frame boundary by the rendering thread; - // schedule a flush so contexts that are not currently rendering still pick - // it up (and present their last offscreen frame). - flushPendingSurfaceTransition(info); -#endif -} - -extern "C" JNIEXPORT void JNICALL -Java_com_shopify_reactnative_skia_WebGPUView_onSurfaceChanged( - JNIEnv *env, jobject thiz, jobject surface, jint contextId, jfloat width, - jfloat height) { -#ifdef SK_GRAPHITE - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto surfaceInfo = registry.getSurfaceInfo(contextId); - if (surfaceInfo) { - surfaceInfo->resize(static_cast(width), static_cast(height)); - } -#endif -} - -extern "C" JNIEXPORT void JNICALL -Java_com_shopify_reactnative_skia_WebGPUView_switchToOffscreenSurface( - JNIEnv *env, jobject thiz, jint contextId) { -#ifdef SK_GRAPHITE - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto surfaceInfo = registry.getSurfaceInfo(contextId); - if (surfaceInfo) { - surfaceInfo->switchToOffscreen(); - } -#endif -} - -extern "C" JNIEXPORT void JNICALL -Java_com_shopify_reactnative_skia_WebGPUView_onViewDestroyed(JNIEnv *env, - jobject thiz, - jint contextId) { -#ifdef SK_GRAPHITE - // The view dies with its Canvas (contextIds are never reused), so view - // teardown retires the registry entry. The JS-side cleanup - // (RNWebGPU.destroyContext) only handles entries that never had a native - // surface; see RNWebGPU::destroyContext for the ownership split. - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - if (auto info = registry.getSurfaceInfo(contextId)) { - info->detachSurface(); - } - registry.removeSurfaceInfo(contextId); -#endif -} diff --git a/packages/skia/android/cpp/rnskia-android/SkiaPlatformContext.h b/packages/skia/android/cpp/rnskia-android/SkiaPlatformContext.h deleted file mode 100644 index 23632892fd..0000000000 --- a/packages/skia/android/cpp/rnskia-android/SkiaPlatformContext.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#ifdef SK_GRAPHITE - -#include "rnwgpu/PlatformContext.h" - -namespace rnwgpu { - -class SkiaPlatformContext : public PlatformContext { -public: - SkiaPlatformContext() = default; - ~SkiaPlatformContext() = default; - - wgpu::Surface makeSurface(wgpu::Instance instance, void *surface, int width, - int height) override { - wgpu::SurfaceDescriptorFromAndroidNativeWindow androidSurfaceDesc; - androidSurfaceDesc.window = surface; - wgpu::SurfaceDescriptor surfaceDescriptor; - surfaceDescriptor.nextInChain = &androidSurfaceDesc; - return instance.CreateSurface(&surfaceDescriptor); - } -}; - -} // namespace rnwgpu - -#endif // SK_GRAPHITE diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java index 08c598a392..52030b2937 100644 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java +++ b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java @@ -43,8 +43,7 @@ public NativeModule getModule(String s, ReactApplicationContext reactApplication @Override public List createViewManagers(ReactApplicationContext reactContext) { return Arrays.asList( - new SkiaPictureViewManager(), - new WebGPUViewManager() + new SkiaPictureViewManager() ); } diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUSurfaceView.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUSurfaceView.java deleted file mode 100644 index 23b6f7008e..0000000000 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUSurfaceView.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.shopify.reactnative.skia; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -import androidx.annotation.NonNull; - -@SuppressLint("ViewConstructor") -public class WebGPUSurfaceView extends SurfaceView implements SurfaceHolder.Callback { - - WebGPUViewAPI mApi; - - public WebGPUSurfaceView(Context context, WebGPUViewAPI api) { - super(context); - mApi = api; - getHolder().addCallback(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - // surfaceDestroyed() normally fires during detach as well; going offscreen - // is idempotent, so this is just a safety net for paths where it does not. - mApi.surfaceOffscreen(); - } - - @Override - public void surfaceCreated(@NonNull SurfaceHolder holder) { - mApi.surfaceCreated(holder.getSurface()); - } - - @Override - public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { - mApi.surfaceChanged(holder.getSurface()); - } - - @Override - public void surfaceDestroyed(@NonNull SurfaceHolder holder) { - mApi.surfaceOffscreen(); - } -} diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUTextureView.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUTextureView.java deleted file mode 100644 index c2b52d1a2c..0000000000 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUTextureView.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.shopify.reactnative.skia; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.SurfaceTexture; -import android.view.Surface; -import android.view.TextureView; -import androidx.annotation.NonNull; - -@SuppressLint("ViewConstructor") -public class WebGPUTextureView extends TextureView implements TextureView.SurfaceTextureListener { - - WebGPUViewAPI mApi; - private Surface mSurface; - - public WebGPUTextureView(Context context, WebGPUViewAPI api) { - super(context); - mApi = api; - setOpaque(false); - setSurfaceTextureListener(this); - } - - @Override - public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) { - mSurface = new Surface(surfaceTexture); - mApi.surfaceCreated(mSurface); - } - - @Override - public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int width, int height) { - mApi.surfaceChanged(mSurface); - } - - @Override - public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) { - // Detach first (synchronous through JNI) so the native side has dropped - // its window reference before we release ours. - mApi.surfaceOffscreen(); - if (mSurface != null) { - mSurface.release(); - mSurface = null; - } - return true; - } - - @Override - public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) { - // No implementation needed - } -} diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUView.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUView.java deleted file mode 100644 index b4cb1330b5..0000000000 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUView.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.shopify.reactnative.skia; - -import android.content.Context; -import android.view.Surface; -import android.view.View; - -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.views.view.ReactViewGroup; - -public class WebGPUView extends ReactViewGroup implements WebGPUViewAPI { - - private int mContextId; - private boolean mTransparent = false; - private View mView = null; - - WebGPUView(Context context) { - super(context); - } - - public void setContextId(int contextId) { - mContextId = contextId; - } - - public void setTransparent(boolean value) { - Context ctx = getContext(); - if (value != mTransparent || mView == null) { - if (mView != null) { - removeView(mView); - } - mTransparent = value; - if (mTransparent) { - mView = new WebGPUTextureView(ctx, this); - } else { - mView = new WebGPUSurfaceView(ctx, this); - } - addView(mView); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (mView != null) { - mView.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight()); - } - } - - @Override - public void surfaceCreated(Surface surface) { - float density = getResources().getDisplayMetrics().density; - float width = getWidth() / density; - float height = getHeight() / density; - onSurfaceCreate(surface, mContextId, width, height); - } - - @Override - public void surfaceChanged(Surface surface) { - float density = getResources().getDisplayMetrics().density; - float width = getWidth() / density; - float height = getHeight() / density; - onSurfaceChanged(surface, mContextId, width, height); - } - - @Override - public void surfaceOffscreen() { - switchToOffscreenSurface(mContextId); - } - - /** - * Called from WebGPUViewManager.onDropViewInstance when React removes this - * view: the view dies with its Canvas, so it retires the registry entry. - */ - public void destroy() { - onViewDestroyed(mContextId); - } - - @DoNotStrip - private native void onSurfaceCreate( - Surface surface, - int contextId, - float width, - float height - ); - - @DoNotStrip - private native void onSurfaceChanged( - Surface surface, - int contextId, - float width, - float height - ); - - @DoNotStrip - private native void switchToOffscreenSurface(int contextId); - - @DoNotStrip - private native void onViewDestroyed(int contextId); -} diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewAPI.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewAPI.java deleted file mode 100644 index 76a8338170..0000000000 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewAPI.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.shopify.reactnative.skia; - -import android.view.Surface; - -/** - * Surface lifecycle events a WebGPU child view reports. The registry entry - * itself is owned by the JS Canvas component (created lazily, removed via - * RNWebGPU.destroyContext on unmount); views only attach and detach surfaces. - * A detached context keeps rendering into an offscreen texture whose content - * is blitted onto the next attached surface. - */ -public interface WebGPUViewAPI { - - void surfaceCreated(Surface surface); - - void surfaceChanged(Surface surface); - - void surfaceOffscreen(); -} diff --git a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewManager.java b/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewManager.java deleted file mode 100644 index df3fc2f720..0000000000 --- a/packages/skia/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewManager.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.shopify.reactnative.skia; - -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.views.view.ReactViewGroup; -import com.facebook.react.views.view.ReactViewManager; -import com.facebook.react.viewmanagers.SkiaWebGPUViewManagerDelegate; -import com.facebook.react.viewmanagers.SkiaWebGPUViewManagerInterface; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -@ReactModule(name = WebGPUViewManager.NAME) -public class WebGPUViewManager extends ReactViewManager implements SkiaWebGPUViewManagerInterface { - - public static final String NAME = "SkiaWebGPUView"; - - protected SkiaWebGPUViewManagerDelegate mDelegate; - - public WebGPUViewManager() { - mDelegate = new SkiaWebGPUViewManagerDelegate(this); - } - - protected SkiaWebGPUViewManagerDelegate getDelegate() { - return mDelegate; - } - - @NonNull - @Override - public String getName() { - return NAME; - } - - @NonNull - @Override - public WebGPUView createViewInstance(@NonNull ThemedReactContext context) { - return new WebGPUView(context); - } - - @Override - @ReactProp(name = "transparent") - public void setTransparent(WebGPUView view, boolean value) { - view.setTransparent(value); - } - - @Override - @ReactProp(name = "contextId") - public void setContextId(WebGPUView view, int value) { - view.setContextId(value); - } - - @Override - public void onDropViewInstance(@NonNull ReactViewGroup view) { - super.onDropViewInstance(view); - ((WebGPUView) view).destroy(); - } -} diff --git a/packages/skia/apple/RNWebGPUAppleNativeBuffer.mm b/packages/skia/apple/RNWebGPUAppleNativeBuffer.mm deleted file mode 100644 index a55a746a93..0000000000 --- a/packages/skia/apple/RNWebGPUAppleNativeBuffer.mm +++ /dev/null @@ -1,33 +0,0 @@ -#ifdef SK_GRAPHITE - -#import - -#include "rnwgpu/api/AppleNativeBuffer.h" - -namespace rnwgpu { - -void *GetIOSurfaceFromNativeBuffer(void *cvPixelBuffer, uint32_t *outWidth, - uint32_t *outHeight) { - auto pixelBuffer = reinterpret_cast(cvPixelBuffer); - if (pixelBuffer == nullptr) { - if (outWidth != nullptr) { - *outWidth = 0; - } - if (outHeight != nullptr) { - *outHeight = 0; - } - return nullptr; - } - if (outWidth != nullptr) { - *outWidth = static_cast(CVPixelBufferGetWidth(pixelBuffer)); - } - if (outHeight != nullptr) { - *outHeight = static_cast(CVPixelBufferGetHeight(pixelBuffer)); - } - // The IOSurface is owned by the CVPixelBuffer; we don't retain it here. - return CVPixelBufferGetIOSurface(pixelBuffer); -} - -} // namespace rnwgpu - -#endif // SK_GRAPHITE diff --git a/packages/skia/apple/SkiaPlatformContext.h b/packages/skia/apple/SkiaPlatformContext.h deleted file mode 100644 index f755309205..0000000000 --- a/packages/skia/apple/SkiaPlatformContext.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef SK_GRAPHITE - -#include "rnwgpu/PlatformContext.h" - -namespace rnwgpu { - -class SkiaPlatformContext : public PlatformContext { -public: - SkiaPlatformContext() = default; - ~SkiaPlatformContext() = default; - - wgpu::Surface makeSurface(wgpu::Instance instance, void *surface, int width, - int height) override; -}; - -} // namespace rnwgpu - -#endif // SK_GRAPHITE diff --git a/packages/skia/apple/SkiaPlatformContext.mm b/packages/skia/apple/SkiaPlatformContext.mm deleted file mode 100644 index 14d391c4e2..0000000000 --- a/packages/skia/apple/SkiaPlatformContext.mm +++ /dev/null @@ -1,21 +0,0 @@ -#ifdef SK_GRAPHITE - -#include "SkiaPlatformContext.h" - -#include - -namespace rnwgpu { - -wgpu::Surface SkiaPlatformContext::makeSurface(wgpu::Instance instance, - void *surface, int width, - int height) { - wgpu::SurfaceSourceMetalLayer metalSurfaceDesc; - metalSurfaceDesc.layer = surface; - wgpu::SurfaceDescriptor surfaceDescriptor; - surfaceDescriptor.nextInChain = &metalSurfaceDesc; - return instance.CreateSurface(&surfaceDescriptor); -} - -} // namespace rnwgpu - -#endif // SK_GRAPHITE diff --git a/packages/skia/apple/SkiaWebGPUView.mm b/packages/skia/apple/SkiaWebGPUView.mm deleted file mode 100644 index 2e2c142263..0000000000 --- a/packages/skia/apple/SkiaWebGPUView.mm +++ /dev/null @@ -1,81 +0,0 @@ -#ifdef RCT_NEW_ARCH_ENABLED - -#import "SkiaWebGPUView.h" - -#import -#import -#import -#import - -#import "RCTFabricComponentsPlugins.h" -#import "WebGPUMetalView.h" - -using namespace facebook::react; - -@implementation SkiaWebGPUView - -- (instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { - static const auto defaultProps = - std::make_shared(); - _props = defaultProps; - } - return self; -} - -+ (ComponentDescriptorProvider)componentDescriptorProvider { - return concreteComponentDescriptorProvider< - SkiaWebGPUViewComponentDescriptor>(); -} - -- (void)prepareForRecycle { - [super prepareForRecycle]; - /* - It's important to destroy the Metal Layer before releasing a view - to the recycled pool to prevent displaying outdated content from - the last usage in the new context. - */ - self.contentView = nil; -} - -- (WebGPUMetalView *)getContentView { - if (!self.contentView) { - self.contentView = [WebGPUMetalView new]; - } - return (WebGPUMetalView *)self.contentView; -} - -- (void)updateProps:(const Props::Shared &)props - oldProps:(const Props::Shared &)oldProps { - const auto &oldViewProps = - *std::static_pointer_cast(_props); - const auto &newViewProps = - *std::static_pointer_cast(props); - - if (newViewProps.contextId != oldViewProps.contextId) { - /* - The context is set only once during mounting the component - and never changes because it isn't available for users to modify. - */ - WebGPUMetalView *metalView = [WebGPUMetalView new]; - self.contentView = metalView; - [metalView setContextId:@(newViewProps.contextId)]; - [metalView configure]; - } - - [super updateProps:props oldProps:oldProps]; -} - -- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics - oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics { - [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; - [(WebGPUMetalView *)self.contentView update]; -} - -@end - -Class SkiaWebGPUViewCls(void) { - return SkiaWebGPUView.class; -} - -#endif // RCT_NEW_ARCH_ENABLED diff --git a/packages/skia/apple/WebGPUMetalView.mm b/packages/skia/apple/WebGPUMetalView.mm deleted file mode 100644 index ad31c7013b..0000000000 --- a/packages/skia/apple/WebGPUMetalView.mm +++ /dev/null @@ -1,136 +0,0 @@ -#import "WebGPUMetalView.h" - -#ifdef SK_GRAPHITE - -#import "webgpu/webgpu_cpp.h" -#import - -#import - -#import "rnskia/RNDawnContext.h" -#import "rnwgpu/SurfaceRegistry.h" -#import "rnwgpu/async/RuntimeContext.h" - -namespace { -// Applies a surface attach latched by the platform UI thread (see -// SurfaceInfo::applyPendingAttach) from the JS thread. Surface attaches are -// normally adopted at the next frame boundary by whichever thread renders; -// this flush covers contexts that are not actively rendering (static -// content), so the last offscreen frame still makes it on screen. Mirrors -// react-native-webgpu's RNWebGPUManager::flushPendingSurfaceTransition. -void flushPendingSurfaceTransition(std::shared_ptr info) { - if (info == nullptr) { - return; - } - auto invoker = rnwgpu::async::RuntimeContext::mainCallInvoker(); - if (invoker == nullptr) { - return; - } - invoker->invokeAsync([info = std::move(info)] { info->applyPendingAttach(); }); -} -} // namespace - -@implementation WebGPUMetalView { - BOOL _isConfigured; -} - -#if !TARGET_OS_OSX -+ (Class)layerClass { - return [CAMetalLayer class]; -} -#else // !TARGET_OS_OSX -- (instancetype)init { - self = [super init]; - if (self) { - self.wantsLayer = true; - self.layer = [CAMetalLayer layer]; - } - return self; -} -#endif // !TARGET_OS_OSX - -- (void)configure { - auto size = self.frame.size; - // Retain the layer for as long as SurfaceInfo holds the pointer: the - // latched attach (and the flush lambda that adopts it) can outlive this - // view, e.g. across a dev reload where the registry is cleared before - // dealloc runs. Balanced by the releaser below. - void *nativeSurface = (void *)CFBridgingRetain(self.layer); - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto &dawnContext = RNSkia::DawnContext::getInstance(); - auto gpu = dawnContext.getWGPUInstance(); - - // Create the surface using Dawn's API directly - wgpu::SurfaceSourceMetalLayer metalSurfaceDesc; - metalSurfaceDesc.layer = nativeSurface; - wgpu::SurfaceDescriptor surfaceDescriptor; - surfaceDescriptor.nextInChain = &metalSurfaceDesc; - auto surface = gpu.CreateSurface(&surfaceDescriptor); - - // Find-or-create + attach runs atomically under the registry lock so a - // concurrent destroyContext cannot orphan this surface. - auto info = registry.attachSurface( - [_contextId intValue], gpu, size.width, size.height, nativeSurface, - surface, [](void *layer) { - // The releaser can run on the rendering thread; CALayer teardown - // belongs on the main thread. - dispatch_async(dispatch_get_main_queue(), ^{ - CFBridgingRelease(layer); - }); - }); - // The attach is adopted at the next frame boundary by the rendering thread; - // schedule a flush so contexts that are not currently rendering still pick - // it up (and present their last offscreen frame). - flushPendingSurfaceTransition(info); -} - -- (void)update { - auto size = self.frame.size; - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto surfaceInfo = registry.getSurfaceInfo([_contextId intValue]); - if (surfaceInfo) { - surfaceInfo->resize(size.width, size.height); - } -} - -- (void)dealloc { - // The view dies with its Canvas (contextIds are never reused), so view - // teardown retires the registry entry. The JS-side cleanup - // (RNWebGPU.destroyContext) only handles entries that never had a native - // surface; see RNWebGPU::destroyContext for the ownership split. - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - if (auto info = registry.getSurfaceInfo([_contextId intValue])) { - info->detachSurface(); - } - registry.removeSurfaceInfo([_contextId intValue]); -} - -@end - -#else // SK_GRAPHITE - -// Stub implementation when GRAPHITE is not enabled -@implementation WebGPUMetalView - -#if !TARGET_OS_OSX -+ (Class)layerClass { - return [CAMetalLayer class]; -} -#else // !TARGET_OS_OSX -- (instancetype)init { - self = [super init]; - return self; -} -#endif // !TARGET_OS_OSX - -- (void)configure { - // No-op when GRAPHITE is not enabled -} - -- (void)update { - // No-op when GRAPHITE is not enabled -} - -@end - -#endif // SK_GRAPHITE diff --git a/packages/skia/cpp/api/JsiSkApi.h b/packages/skia/cpp/api/JsiSkApi.h index 675935bba3..0690916f20 100644 --- a/packages/skia/cpp/api/JsiSkApi.h +++ b/packages/skia/cpp/api/JsiSkApi.h @@ -8,8 +8,6 @@ #ifdef SK_GRAPHITE #include "rnskia/RNDawnContext.h" -#include "rnwgpu/api/GPUDevice.h" -#include "rnwgpu/async/RuntimeContext.h" #endif #include "JsiNativeBuffer.h" @@ -173,36 +171,27 @@ class JsiSkApi : public JsiSkNativeObject { JSI_HOST_FUNCTION(Color) { return JsiSkColor::createCtor()(runtime, thisValue, arguments, count); } - JSI_HOST_FUNCTION(Recorder) { - return JsiRecorder::createCtor(getContext())(runtime, thisValue, arguments, - count); - } - - bool hasDevice() { -#ifdef SK_GRAPHITE - return true; -#else - return false; -#endif - } - - JSI_HOST_FUNCTION(getDevice) { + JSI_HOST_FUNCTION(getNativeDevice) { #ifdef SK_GRAPHITE + // Raw WGPUDevice pointer of the Graphite device, as a BigInt. Consumed by + // react-native-webgpu's importDevice(), which AddRefs it; the pointer + // stays owned by DawnContext and is valid for the process lifetime. auto &dawnContext = DawnContext::getInstance(); - // Per-runtime context: async ops on this device resolve on the calling - // runtime's own thread (via its ProcessEvents pump). - auto context = rnwgpu::async::RuntimeContext::getOrCreate( - runtime, dawnContext.getWGPUInstance()); - auto device = std::make_shared( - dawnContext.getWGPUDevice(), context, "Skia Device"); - return rnwgpu::GPUDevice::create(runtime, device); + return jsi::BigInt::fromUint64( + runtime, + reinterpret_cast(dawnContext.getWGPUDevice().Get())); #else throw jsi::JSError(runtime, - "getDevice() is only available with the Graphite " + "getNativeDevice() is only available with the Graphite " "backend. Rebuild with SK_GRAPHITE enabled."); #endif } + JSI_HOST_FUNCTION(Recorder) { + return JsiRecorder::createCtor(getContext())(runtime, thisValue, arguments, + count); + } + // Factory properties: like the legacy HostObject implementation, each // property access returns a fresh JS wrapper around the shared factory // instance. @@ -268,6 +257,8 @@ class JsiSkApi : public JsiSkNativeObject { static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { installHostMethod(runtime, prototype, "Video", &JsiSkApi::Video); installHostMethod(runtime, prototype, "Context", &JsiSkApi::Context); + installHostMethod(runtime, prototype, "getNativeDevice", + &JsiSkApi::getNativeDevice); installHostMethod(runtime, prototype, "Font", &JsiSkApi::Font); installHostMethod(runtime, prototype, "Paint", &JsiSkApi::Paint); installHostMethod(runtime, prototype, "RSXform", &JsiSkApi::RSXform); @@ -287,8 +278,6 @@ class JsiSkApi : public JsiSkNativeObject { &JsiSkApi::PictureRecorder); installHostMethod(runtime, prototype, "Color", &JsiSkApi::Color); installHostMethod(runtime, prototype, "Recorder", &JsiSkApi::Recorder); - installMethod(runtime, prototype, "hasDevice", &JsiSkApi::hasDevice); - installHostMethod(runtime, prototype, "getDevice", &JsiSkApi::getDevice); installGetter(runtime, prototype, "SVG", &JsiSkApi::getSVGFactory); installGetter(runtime, prototype, "Image", &JsiSkApi::getImageFactory); installGetter(runtime, prototype, "AnimatedImage", diff --git a/packages/skia/cpp/api/JsiSkImageFactory.h b/packages/skia/cpp/api/JsiSkImageFactory.h index 67198e55e8..2d248ffd7d 100644 --- a/packages/skia/cpp/api/JsiSkImageFactory.h +++ b/packages/skia/cpp/api/JsiSkImageFactory.h @@ -15,7 +15,6 @@ #ifdef SK_GRAPHITE #include "rnskia/RNDawnContext.h" -#include "rnwgpu/api/GPUTexture.h" #endif namespace RNSkia { @@ -103,62 +102,73 @@ class JsiSkImageFactory : public JsiSkNativeObject { runtime, std::make_shared(getContext(), std::move(image))); } - JSI_HOST_FUNCTION(MakeImageFromTexture) { + // Pointer-based texture interop with react-native-webgpu. The GPUTexture + // JS objects live in react-native-webgpu, so textures cross the package + // boundary as raw WGPUTexture pointers (BigInt), exactly like the device + // handoff (Skia.getNativeDevice / importDevice). Only sound on the shared + // device: both packages link one Dawn and share one wgpu::Instance. + + JSI_HOST_FUNCTION(MakeImageFromNativeTexture) { #ifdef SK_GRAPHITE - if (count < 1 || !arguments[0].isObject()) { - throw std::runtime_error( - "MakeImageFromTexture requires a GPUTexture argument"); + if (count < 1 || !arguments[0].isBigInt()) { + throw std::runtime_error("MakeImageFromNativeTexture requires a " + "WGPUTexture pointer (BigInt), e.g. " + "texture.nativePointer"); } - auto obj = arguments[0].asObject(runtime); - auto gpuTexture = obj.getNativeState(runtime); - if (!gpuTexture) { - throw std::runtime_error("Invalid GPUTexture object"); + auto raw = reinterpret_cast( + arguments[0].asBigInt(runtime).asUint64(runtime)); + if (raw == nullptr) { + throw std::runtime_error( + "MakeImageFromNativeTexture: pointer must be non-null"); } - - wgpu::Texture texture = gpuTexture->get(); - int width = static_cast(gpuTexture->getWidth()); - int height = static_cast(gpuTexture->getHeight()); - wgpu::TextureFormat format = gpuTexture->getFormat(); - + // Borrow: AddRef so our wgpu::Texture holds its own reference; the + // wrapped SkImage retains the texture for its lifetime (see + // DawnContext::MakeImageFromTexture) and the caller keeps ownership of + // the JS GPUTexture. + wgpuTextureAddRef(raw); + wgpu::Texture texture = wgpu::Texture::Acquire(raw); auto &dawnContext = DawnContext::getInstance(); - auto image = - dawnContext.MakeImageFromTexture(texture, width, height, format); + auto image = dawnContext.MakeImageFromTexture( + texture, static_cast(texture.GetWidth()), + static_cast(texture.GetHeight()), texture.GetFormat()); if (image == nullptr) { - throw std::runtime_error("Failed to create SkImage from GPUTexture!"); + throw std::runtime_error( + "MakeImageFromNativeTexture: failed to wrap the texture"); } return makeJsiObject( runtime, std::make_shared(getContext(), std::move(image))); #else throw std::runtime_error( - "MakeImageFromTexture is only available with the Graphite backend. " - "Rebuild with SK_GRAPHITE enabled."); + "MakeImageFromNativeTexture is only available with the Graphite " + "backend. Rebuild with SK_GRAPHITE enabled."); #endif } - JSI_HOST_FUNCTION(MakeTextureFromImage) { + JSI_HOST_FUNCTION(MakeNativeTextureFromImage) { #ifdef SK_GRAPHITE if (count < 1) { throw std::runtime_error( - "MakeTextureFromImage requires an SkImage argument"); + "MakeNativeTextureFromImage requires an SkImage argument"); } auto image = JsiSkImage::fromValue(runtime, arguments[0]); if (!image) { throw std::runtime_error("Invalid SkImage object"); } - auto &dawnContext = DawnContext::getInstance(); wgpu::Texture texture = dawnContext.MakeTextureFromImage(image); if (!texture) { - throw std::runtime_error("Failed to create GPUTexture from SkImage!"); + throw std::runtime_error( + "MakeNativeTextureFromImage: failed to create the texture"); } - - auto gpuTexture = - std::make_shared(texture, "SkImage Texture"); - return rnwgpu::GPUTexture::create(runtime, gpuTexture); + // Transfer ownership: the returned pointer carries one reference and must + // be adopted exactly once (react-native-webgpu's adoptTexture()), which + // releases it when the JS GPUTexture is destroyed. + return jsi::BigInt::fromUint64( + runtime, reinterpret_cast(texture.MoveToCHandle())); #else throw std::runtime_error( - "MakeTextureFromImage is only available with the Graphite backend. " - "Rebuild with SK_GRAPHITE enabled."); + "MakeNativeTextureFromImage is only available with the Graphite " + "backend. Rebuild with SK_GRAPHITE enabled."); #endif } @@ -176,10 +186,10 @@ class JsiSkImageFactory : public JsiSkNativeObject { installMethod(runtime, prototype, "MakeImage", &JsiSkImageFactory::MakeImage); installMethod(runtime, prototype, "MakeNull", &JsiSkImageFactory::MakeNull); - installHostMethod(runtime, prototype, "MakeImageFromTexture", - &JsiSkImageFactory::MakeImageFromTexture); - installHostMethod(runtime, prototype, "MakeTextureFromImage", - &JsiSkImageFactory::MakeTextureFromImage); + installHostMethod(runtime, prototype, "MakeImageFromNativeTexture", + &JsiSkImageFactory::MakeImageFromNativeTexture); + installHostMethod(runtime, prototype, "MakeNativeTextureFromImage", + &JsiSkImageFactory::MakeNativeTextureFromImage); } explicit JsiSkImageFactory(std::shared_ptr context) diff --git a/packages/skia/cpp/jsi/JSIConverter.h b/packages/skia/cpp/jsi/JSIConverter.h index 6862109ae7..f68bc03dd8 100644 --- a/packages/skia/cpp/jsi/JSIConverter.h +++ b/packages/skia/cpp/jsi/JSIConverter.h @@ -17,11 +17,6 @@ #include "EnumMapper.h" #include "Promise.h" -#ifdef SK_GRAPHITE -#include "rnwgpu/api/descriptors/Unions.h" -#include "rnwgpu/async/AsyncTaskHandle.h" -#endif - // This number is the maximum integer that can be represented exactly as a // double #define MAX_SAFE_INTEGER static_cast(9007199254740991) @@ -212,32 +207,6 @@ struct JSIConverter::value>> { } }; -#ifdef SK_GRAPHITE -// AsyncTaskHandle <> Promise -template <> struct JSIConverter { - static rnwgpu::async::AsyncTaskHandle fromJSI(jsi::Runtime &, - const jsi::Value &, bool) { - throw std::runtime_error( - "Cannot convert a Promise to AsyncTaskHandle on the native side."); - } - - static jsi::Value toJSI(jsi::Runtime &runtime, - rnwgpu::async::AsyncTaskHandle &&handle) { - return rnwgpu::Promise::createPromise( - runtime, [handle = std::move(handle)]( - jsi::Runtime &runtime, - std::shared_ptr promise) mutable { - if (!handle.valid()) { - promise->resolve(jsi::Value::undefined()); - return; - } - - handle.attachPromise(promise); - }); - } -}; -#endif - // jsi::Function <> Function template <> struct JSIConverter { static jsi::Function fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, diff --git a/packages/skia/cpp/rnskia/RNDawnContext.h b/packages/skia/cpp/rnskia/RNDawnContext.h index aabf4bf0ab..ac028fd255 100644 --- a/packages/skia/cpp/rnskia/RNDawnContext.h +++ b/packages/skia/cpp/rnskia/RNDawnContext.h @@ -366,8 +366,9 @@ class DawnContext { std::mutex _mutex; DawnContext() { - DawnProcTable backendProcs = dawn::native::GetProcs(); - dawnProcSetProcs(&backendProcs); + // No dawnProcSetProcs() here: the monolithic libwebgpu_dawn (shared with + // react-native-webgpu) exposes the real wgpu* C entry points directly + // rather than the settable dawn_proc trampoline, which it does not ship. static const auto kTimedWaitAny = wgpu::InstanceFeatureName::TimedWaitAny; wgpu::InstanceDescriptor instanceDesc{.requiredFeatureCount = 1, @@ -376,6 +377,21 @@ class DawnContext { // For limits: wgpu::InstanceLimits limits{.timedWaitAnyMaxCount = 64}; instanceDesc.requiredLimits = &limits; + + // Same instance-stage toggles react-native-webgpu sets on its own + // instance: when webgpu adopts this instance (rnskia_getWGPUInstance), + // its external-texture path expects experimental adapter features to be + // visible. These only un-hide features in adapter.features; nothing + // becomes active unless a device requests it. + static const char *const kInstanceToggles[] = { + "allow_unsafe_apis", + "expose_wgsl_experimental_features", + }; + wgpu::DawnTogglesDescriptor instanceToggles; + instanceToggles.enabledToggleCount = std::size(kInstanceToggles); + instanceToggles.enabledToggles = kInstanceToggles; + instanceDesc.nextInChain = &instanceToggles; + instance = std::make_unique(&instanceDesc); backendContext = DawnUtils::createDawnBackendContext(instance.get()); diff --git a/packages/skia/cpp/rnskia/RNDawnInterop.cpp b/packages/skia/cpp/rnskia/RNDawnInterop.cpp new file mode 100644 index 0000000000..952968f8fc --- /dev/null +++ b/packages/skia/cpp/rnskia/RNDawnInterop.cpp @@ -0,0 +1,19 @@ +#ifdef SK_GRAPHITE + +#include "RNDawnContext.h" + +// Runtime discovery surface for react-native-webgpu. +// +// webgpu looks this symbol up with dlsym(RTLD_DEFAULT, ...) when it creates +// its GPU object and, when found, adopts the returned instance instead of +// creating its own. Sharing one wgpu::Instance across both packages makes +// pointer-based device handoff (RNWebGPU.importDevice(Skia.getNativeDevice())) +// sound: async callbacks of imported devices settle on the instance webgpu +// pumps. Plain C, default visibility: no C++ ABI surface, works across +// separately compiled pods, and stays dlsym-able under -fvisibility=hidden. +extern "C" __attribute__((visibility("default"))) WGPUInstance +rnskia_getWGPUInstance() { + return RNSkia::DawnContext::getInstance().getWGPUInstance().Get(); +} + +#endif diff --git a/packages/skia/cpp/rnskia/RNDawnUtils.h b/packages/skia/cpp/rnskia/RNDawnUtils.h index d1a0f2190d..4100a3eeee 100644 --- a/packages/skia/cpp/rnskia/RNDawnUtils.h +++ b/packages/skia/cpp/rnskia/RNDawnUtils.h @@ -1,8 +1,11 @@ #pragma once +#if defined(__APPLE__) +#include +#endif + #include "webgpu/webgpu_cpp.h" -#include "dawn/dawn_proc.h" #include "dawn/native/DawnNative.h" #include "include/core/SkColorType.h" @@ -115,6 +118,20 @@ requestDevice(dawn::native::Adapter &nativeAdapter, wgpu::DawnTogglesDescriptor togglesDesc; togglesDesc.enabledToggleCount = std::size(kToggles); togglesDesc.enabledToggles = kToggles; +#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR + // The iOS Simulator only advertises MTLFeatureSet_iOS_GPUFamily2, so Dawn + // defaults disable_base_instance/disable_base_vertex on and then rejects + // every draw with a non-zero firstInstance or baseVertex, which Graphite + // emits routinely. The simulator forwards Metal calls to the host GPU, + // which does support base vertex/instance drawing, so force the toggles + // off. Device builds are unaffected: Graphite-capable iPhones and iPads + // are all GPUFamily3+. (Same override as react-native-webgpu; see + // https://issues.chromium.org/issues/42241591.) + static constexpr const char *kDisabledToggles[] = {"disable_base_instance", + "disable_base_vertex"}; + togglesDesc.disabledToggleCount = std::size(kDisabledToggles); + togglesDesc.disabledToggles = kDisabledToggles; +#endif wgpu::DeviceDescriptor desc; desc.requiredFeatureCount = features.size(); diff --git a/packages/skia/cpp/rnskia/RNSkManager.cpp b/packages/skia/cpp/rnskia/RNSkManager.cpp index a9353141ac..d811df1f55 100644 --- a/packages/skia/cpp/rnskia/RNSkManager.cpp +++ b/packages/skia/cpp/rnskia/RNSkManager.cpp @@ -11,27 +11,6 @@ #include "jsi/RuntimeAwareCache.h" -#ifdef SK_GRAPHITE -#include "RNDawnContext.h" -#include "jsi/Promise.h" -#include "rnwgpu/ArrayBuffer.h" -#include "rnwgpu/api/GPU.h" -#include "rnwgpu/api/GPUUncapturedErrorEvent.h" -#include "rnwgpu/api/ImageBitmap.h" -#include "rnwgpu/api/RNWebGPU.h" -#include "rnwgpu/api/WebGPUConstants.h" -#include "rnwgpu/api/descriptors/GPUBufferUsage.h" -#include "rnwgpu/api/descriptors/GPUColorWrite.h" -#include "rnwgpu/api/descriptors/GPUMapMode.h" -#include "rnwgpu/api/descriptors/GPUShaderStage.h" -#include "rnwgpu/api/descriptors/GPUTextureUsage.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "include/core/SkData.h" -#include "include/core/SkImage.h" -#include "include/core/SkImageInfo.h" -#endif - namespace RNSkia { namespace jsi = facebook::jsi; @@ -43,7 +22,7 @@ RNSkManager::RNSkManager( _jsCallInvoker(jsCallInvoker), _viewApi(std::make_shared(platformContext)) { - // Register main runtime (used by both Skia and WebGPU bindings) + // Register main runtime RNJsi::BaseRuntimeAwareCache::setMainJsRuntime(_jsRuntime); // Install bindings @@ -51,12 +30,6 @@ RNSkManager::RNSkManager( } RNSkManager::~RNSkManager() { -#ifdef SK_GRAPHITE - // Drop all canvas registry entries: after a reload the JS side restarts its - // contextId counter, and stale entries would alias new canvases onto dead - // surfaces. - rnwgpu::SurfaceRegistry::getInstance().clear(); -#endif // Free up any references _viewApi = nullptr; _jsRuntime = nullptr; @@ -87,139 +60,9 @@ void RNSkManager::installBindings() { _jsRuntime->global().setProperty(*_jsRuntime, "SkiaViewApi", makeJsiObject(*_jsRuntime, _viewApi)); -#ifdef SK_GRAPHITE - // Register the main runtime + its CallInvoker so spontaneous events - // (device.lost / uncapturederror) on main-runtime devices can be delivered to - // the JS thread without the ProcessEvents pump. Worklet-runtime devices have - // no invoker (best-effort; see the RuntimeContext "Threading model" doc). - rnwgpu::async::RuntimeContext::registerMainRuntime(_jsRuntime, - _jsCallInvoker); - - // Install WebGPU constructors - rnwgpu::GPU::installConstructor(*_jsRuntime); - rnwgpu::GPUUncapturedErrorEvent::installConstructor(*_jsRuntime); - // Create and expose navigator.gpu using DawnContext's instance - auto &dawnContext = DawnContext::getInstance(); - auto gpu = - std::make_shared(*_jsRuntime, dawnContext.getWGPUInstance()); - auto navigatorValue = - _jsRuntime->global().getProperty(*_jsRuntime, "navigator"); - if (navigatorValue.isObject()) { - auto navigator = navigatorValue.asObject(*_jsRuntime); - navigator.setProperty(*_jsRuntime, "gpu", - rnwgpu::GPU::create(*_jsRuntime, gpu)); - } else { - // Create navigator object if it doesn't exist - jsi::Object navigator(*_jsRuntime); - navigator.setProperty(*_jsRuntime, "gpu", - rnwgpu::GPU::create(*_jsRuntime, gpu)); - _jsRuntime->global().setProperty(*_jsRuntime, "navigator", - std::move(navigator)); - } - - // Install WebGPU constant objects as plain JS objects on the main runtime. - rnwgpu::installWebGPUConstants(*_jsRuntime); - - // Install a global `installWebGPU()` host function so worklet runtimes can - // get the same constants. A host function captured into a worklet is - // serialized as a SerializableHostFunction and re-created on the worklet - // runtime, so the body runs there (its `rt` is the worklet runtime) and - // installs the constants on that runtime. The constants come from the native - // wgpu::*Usage enums, so the values stay a single source of truth across - // every runtime. Calling it on a runtime that already has the globals is a - // safe, idempotent no-op. - _jsRuntime->global().setProperty( - *_jsRuntime, "installWebGPU", - jsi::Function::createFromHostFunction( - *_jsRuntime, jsi::PropNameID::forAscii(*_jsRuntime, "installWebGPU"), - 0, - [](jsi::Runtime &rt, const jsi::Value & /*thisVal*/, - const jsi::Value * /*args*/, size_t /*count*/) -> jsi::Value { - rnwgpu::installWebGPUConstants(rt); - return jsi::Value::undefined(); - })); - - // Install RNWebGPU global object for WebGPU Canvas support - auto rnWebGPU = std::make_shared(gpu, nullptr); - _jsRuntime->global().setProperty( - *_jsRuntime, "RNWebGPU", rnwgpu::RNWebGPU::create(*_jsRuntime, rnWebGPU)); - - // DRAFT — compile-unverified. Install the ImageBitmap constructor (so - // `instanceof ImageBitmap` works) and a global createImageBitmap() that - // accepts the non-standard encoded-BufferSource overload. - // - // The BufferSource is run through the shared rnwgpu::ArrayBuffer converter, - // which validates byteOffset/byteLength against the backing buffer and throws - // synchronously on a spoofed / out-of-bounds view — so createImageBitmap() - // rejects rather than reading out of bounds (see ArrayBufferBounds / - // ImageBitmapBounds specs). Decoding uses Skia's own codec; no platform image - // decoder is needed. - rnwgpu::ImageBitmap::installConstructor(*_jsRuntime); - _jsRuntime->global().setProperty( - *_jsRuntime, "createImageBitmap", - jsi::Function::createFromHostFunction( - *_jsRuntime, - jsi::PropNameID::forAscii(*_jsRuntime, "createImageBitmap"), 1, - [](jsi::Runtime &rt, const jsi::Value & /*thisVal*/, - const jsi::Value *args, size_t count) -> jsi::Value { - if (count < 1 || !args[0].isObject()) { - throw jsi::JSError( - rt, "createImageBitmap requires a BufferSource argument"); - } - // Only the encoded ArrayBuffer / ArrayBufferView overload is - // supported here. Anything else (Blob, ImageData, …) is rejected. - auto obj = args[0].getObject(rt); - bool isBufferSource = obj.isArrayBuffer(rt); - if (!isBufferSource && obj.hasProperty(rt, "buffer")) { - auto bufferProp = obj.getProperty(rt, "buffer"); - isBufferSource = bufferProp.isObject() && - bufferProp.getObject(rt).isArrayBuffer(rt); - } - if (!isBufferSource) { - throw jsi::JSError(rt, "createImageBitmap: unsupported source " - "(expected an ArrayBuffer or TypedArray " - "of encoded image bytes)"); - } - // Validates bounds and THROWS synchronously on a spoofed view, so - // the bad pointer never reaches the copy below. - auto buffer = rnwgpu::JSIConverter< - std::shared_ptr>::fromJSI(rt, args[0], - false); - // Copy the encoded bytes off the JS-owned ArrayBuffer. - const uint8_t *bytes = buffer->data(); - std::vector encoded(bytes, bytes + buffer->size()); - - return rnwgpu::Promise::createPromise( - rt, [encoded = std::move(encoded)]( - jsi::Runtime &runtime, - std::shared_ptr promise) mutable { - auto skData = - SkData::MakeWithCopy(encoded.data(), encoded.size()); - auto image = SkImages::DeferredFromEncodedData(skData); - if (image == nullptr) { - promise->reject( - "createImageBitmap: failed to decode image data"); - return; - } - const int w = image->width(); - const int h = image->height(); - auto info = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, - kUnpremul_SkAlphaType); - std::vector pixels(info.computeMinByteSize()); - // nullptr context: decode/read on the CPU (raster). - if (!image->readPixels(nullptr, info, pixels.data(), - info.minRowBytes(), 0, 0)) { - promise->reject( - "createImageBitmap: failed to read decoded pixels"); - return; - } - auto bitmap = std::make_shared( - std::move(pixels), static_cast(w), - static_cast(h)); - promise->resolve( - rnwgpu::ImageBitmap::create(runtime, bitmap)); - }); - })); -#endif + // The WebGPU JS API (RNWebGPU, navigator.gpu, constants, createImageBitmap) + // is no longer installed here: react-native-webgpu is the single WebGPU API + // surface for React Native. Graphite keeps Dawn as an internal + // implementation detail only. } } // namespace RNSkia diff --git a/packages/skia/cpp/rnwgpu/ArrayBuffer.h b/packages/skia/cpp/rnwgpu/ArrayBuffer.h deleted file mode 100644 index 3d4544ced6..0000000000 --- a/packages/skia/cpp/rnwgpu/ArrayBuffer.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once -#include - -#include -#include -#include - -#include "jsi/JSIConverter.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -struct ArrayBuffer : jsi::MutableBuffer { - ArrayBuffer(void *data, size_t size, size_t bytesPerElement) - : _data(data), _size(size), _bytesPerElement(bytesPerElement) {} - - ~ArrayBuffer() override {} - - size_t size() const override { return _size; } - - uint8_t *data() override { return static_cast(_data); } - - void *_data; - size_t _size; - size_t _bytesPerElement; -}; - -static std::shared_ptr -createArrayBufferFromJSI(jsi::Runtime &runtime, - const jsi::ArrayBuffer &arrayBuffer, - size_t bytesPerElement) { - auto size = arrayBuffer.size(runtime); - return std::make_shared(arrayBuffer.data(runtime), size, - bytesPerElement); -} - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBound) { - if (arg.isObject()) { - auto obj = arg.getObject(runtime); - if (obj.isArrayBuffer(runtime)) { - return createArrayBufferFromJSI(runtime, obj.getArrayBuffer(runtime), - 1); - } - if (obj.hasProperty(runtime, "buffer")) { - auto bufferProp = obj.getProperty(runtime, "buffer"); - if (bufferProp.isObject() && - bufferProp.getObject(runtime).isArrayBuffer(runtime)) { - auto buff = bufferProp.getObject(runtime); - auto arrayBuffer = buff.getArrayBuffer(runtime); - const size_t bufferSize = arrayBuffer.size(runtime); - - // byteOffset / byteLength are user-readable JS properties, not values - // the engine guarantees (unlike Dawn's node binding, which reads them - // off the engine's typed-array view). Read them as doubles so we can - // reject negative, non-integral, NaN/Inf, or oversized values before - // they wrap around when cast to size_t. - const double byteOffsetValue = - obj.getProperty(runtime, "byteOffset").asNumber(); - const double byteLengthValue = - obj.getProperty(runtime, "byteLength").asNumber(); - - auto isValidByteIndex = [](double value) { - return std::isfinite(value) && value >= 0.0 && - value <= static_cast(SIZE_MAX) && - std::floor(value) == value; - }; - if (!isValidByteIndex(byteOffsetValue) || - !isValidByteIndex(byteLengthValue)) { - throw std::runtime_error( - "ArrayBuffer::fromJSI: invalid byteOffset/byteLength"); - } - - const size_t byteOffset = static_cast(byteOffsetValue); - const size_t byteLength = static_cast(byteLengthValue); - - // Overflow-safe bounds check: byteOffset + byteLength <= bufferSize. - if (byteOffset > bufferSize || byteLength > bufferSize - byteOffset) { - throw std::runtime_error( - "ArrayBuffer::fromJSI: view bounds [byteOffset, byteOffset + " - "byteLength) exceed the backing ArrayBuffer size"); - } - - // BYTES_PER_ELEMENT is absent on a DataView; default to 1. A spoofed - // object could report 0 (or a negative/NaN value), so clamp to a - // minimum of 1 to avoid a later division by zero in writeBuffer. - size_t bytesPerElements = 1; - if (obj.hasProperty(runtime, "BYTES_PER_ELEMENT")) { - auto bpe = obj.getProperty(runtime, "BYTES_PER_ELEMENT"); - if (bpe.isNumber()) { - const double value = bpe.asNumber(); - if (std::isfinite(value) && value >= 1.0) { - bytesPerElements = static_cast(value); - } - } - } - - return std::make_shared(arrayBuffer.data(runtime) + - byteOffset, - byteLength, bytesPerElements); - } - } - } - throw std::runtime_error("ArrayBuffer::fromJSI: argument is not an object " - "with an ArrayBuffer 'buffer' property"); - } - - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - return jsi::ArrayBuffer(runtime, arg); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/Canvas.h b/packages/skia/cpp/rnwgpu/Canvas.h deleted file mode 100644 index be3a34461b..0000000000 --- a/packages/skia/cpp/rnwgpu/Canvas.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class Canvas : public NativeObject { -public: - // Note: not "Canvas" — that brand belongs to RNSkia::JsiSkCanvas, and - // boxing brands must be unique process-wide (see BoxedNativeObjectRegistry). - static constexpr const char *CLASS_NAME = "WebGPUCanvas"; - - Canvas(void *nativeSurface, int width, int height) - : NativeObject(CLASS_NAME), _nativeSurface(nativeSurface), _width(width), - _height(height), _clientWidth(width), _clientHeight(height) {} - - void *getNativeSurface() { return _nativeSurface; } - - int getWidth() { return _width; } - int getHeight() { return _height; } - - void setWidth(int width) { _width = width; } - void setHeight(int height) { _height = height; } - - int getClientWidth() { return _clientWidth; } - int getClientHeight() { return _clientHeight; } - - void setClientWidth(int width) { _clientWidth = width; } - void setClientHeight(int height) { _clientHeight = height; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetterSetter(runtime, prototype, "width", &Canvas::getWidth, - &Canvas::setWidth); - installGetterSetter(runtime, prototype, "height", &Canvas::getHeight, - &Canvas::setHeight); - installGetter(runtime, prototype, "clientWidth", &Canvas::getClientWidth); - installGetter(runtime, prototype, "clientHeight", &Canvas::getClientHeight); - } - -private: - void *_nativeSurface; - int _width; - int _height; - int _clientWidth; - int _clientHeight; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/PlatformContext.h b/packages/skia/cpp/rnwgpu/PlatformContext.h deleted file mode 100644 index 988ffb5ab9..0000000000 --- a/packages/skia/cpp/rnwgpu/PlatformContext.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -class PlatformContext { -public: - PlatformContext() = default; - virtual ~PlatformContext() = default; - - virtual wgpu::Surface makeSurface(wgpu::Instance instance, void *surface, - int width, int height) = 0; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/SurfaceRegistry.h b/packages/skia/cpp/rnwgpu/SurfaceRegistry.h deleted file mode 100644 index 72affffb2b..0000000000 --- a/packages/skia/cpp/rnwgpu/SurfaceRegistry.h +++ /dev/null @@ -1,605 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#ifdef __APPLE__ -#include "rnskia/RNMetalLayerColorSpace.h" - -namespace dawn::native::metal { -void WaitForCommandsToBeScheduled(WGPUDevice device); -} // namespace dawn::native::metal -#endif - -namespace rnwgpu { - -struct NativeInfo { - void *nativeSurface; - int width; - int height; -}; - -struct Size { - int width; - int height; -}; - -// Invoked with the platform's native surface pointer once SurfaceInfo is done -// with it, so the platform can drop the reference it acquired on our behalf -// (ANativeWindow_release on Android, CFBridgingRelease of the retained -// CAMetalLayer on Apple platforms). May run on any thread. -using NativeSurfaceReleaser = std::function; - -// Bridges the asynchronous native surface lifecycle (surfaces appear and -// disappear on the platform UI thread) with the synchronous WebGPU canvas API -// (the JS render loop must always be able to acquire a texture). -// -// Ownership & threading model: -// - A registry entry is created on first use (by whichever of JS/native gets -// there first) and lives exactly as long as its JS Canvas: contextIds are -// never reused. It is removed by the native view's teardown (WebGPUMetalView -// dealloc / WebGPUViewManager.onDropViewInstance) when a surface is -// attached, or by RNWebGPU.destroyContext (the Canvas unmount cleanup) when -// none ever was — see RNWebGPU::destroyContext for why the split. Surface -// destruction alone (backgrounding, TextureView teardown) never removes an -// entry; it only detaches the surface. -// - Attaching a surface is LATCHED: the UI thread stores it as pending -// (attachSurface) and it is adopted at the next frame boundary — start of -// getCurrentTexture or end of presentFrame — on whichever thread renders -// (main JS, Reanimated UI, or a worklet runtime). This preserves Dawn -// surface thread-affinity and guarantees a surface is never swapped in the -// middle of a frame. For contexts that are not actively rendering, the -// platform view schedules applyPendingAttach on the JS thread instead (see -// flushPendingSurfaceTransition in WebGPUMetalView / JniWebGPUView). -// - Detaching (switchToOffscreen) is IMMEDIATE, because the platform destroys -// the surface as soon as its callback returns. A configured context falls -// back to rendering into an offscreen texture, so a running render loop -// keeps working; the in-flight frame, if any, is dropped at present(). When -// a new surface attaches, the latest offscreen frame is blitted onto it so -// content appears without waiting for the next render — the same mechanism -// that gives a fast time-to-first-frame when rendering starts before the -// native surface exists. -class SurfaceInfo { -public: - SurfaceInfo(wgpu::Instance gpu, int width, int height) - : _gpu(std::move(gpu)), _width(width), _height(height) {} - - ~SurfaceInfo() { - // Drop the Dawn objects before releasing the native surfaces they borrow. - _surface = nullptr; - _pendingSurface = nullptr; - _texture = nullptr; - if (_pendingReleaser && _pendingNativeSurface) { - _pendingReleaser(_pendingNativeSurface); - } - if (_releaser && _nativeSurface) { - _releaser(_nativeSurface); - } - } - - // --- Platform UI thread --------------------------------------------------- - - // Store a newly created on-screen surface. It becomes active at the next - // frame boundary (applyPendingAttach); callers should follow up with - // flushPendingSurfaceTransition so contexts that are not currently rendering - // also pick it up. - void attachSurface(void *nativeSurface, wgpu::Surface surface, - NativeSurfaceReleaser releaser) { - void *replacedSurface = nullptr; - NativeSurfaceReleaser replacedReleaser; - { - std::unique_lock lock(_mutex); - if (_hasPendingAttach) { - // Replaced before it was ever adopted. - replacedSurface = _pendingNativeSurface; - replacedReleaser = std::move(_pendingReleaser); - } - _hasPendingAttach = true; - _pendingNativeSurface = nativeSurface; - _pendingSurface = std::move(surface); - _pendingReleaser = std::move(releaser); - } - if (replacedReleaser && replacedSurface) { - replacedReleaser(replacedSurface); - } - } - - // The platform surface is being destroyed: detach immediately. If the - // context is configured, rendering continues into an offscreen texture whose - // content is blitted to the next attached surface; present() no-ops until - // then. Safe to call when already offscreen. - void switchToOffscreen() { detach(/* createFallbackTexture = */ true); } - - // Detach without creating the offscreen fallback: used when the context is - // being destroyed and nothing will consume further frames. - void detachSurface() { detach(/* createFallbackTexture = */ false); } - - // Reflects native view layout changes. Does not resize the drawing buffer: - // that tracks canvas.width/height (like on the web), see - // GPUCanvasContext::getCurrentTexture. - void resize(int newWidth, int newHeight) { - std::unique_lock lock(_mutex); - _width = newWidth; - _height = newHeight; - } - - // --- Frame boundary (rendering thread, or the JS thread via - // flushPendingSurfaceTransition) ------------------------------------------- - - // Adopt a pending surface if no frame is in flight: configure it and, if - // frames were rendered offscreen, blit the most recent one onto it and - // present it, so content shows up without waiting for the render loop. - // Safe to call from any thread; no-ops when there is nothing pending. - // - // supersedeInFlightFrame is set by the rendering thread when it starts a new - // frame: a previous frame that never presented is abandoned and must not - // block adoption. The flush path (other threads) leaves it false so it never - // swaps the surface under a frame that is genuinely in flight. - void applyPendingAttach(bool supersedeInFlightFrame = false) { - bool presentBlit = false; - uint64_t blitEpoch = 0; - wgpu::Device device = nullptr; - void *replacedSurface = nullptr; - NativeSurfaceReleaser replacedReleaser; - { - std::unique_lock lock(_mutex); - if (supersedeInFlightFrame) { - _frameInFlight = false; - _acquiredFromSurface = false; - } - if (!_hasPendingAttach || _frameInFlight) { - return; - } - // Attach over attach without a detach in between: replace. Ownership - // tracks the native window pointer, not the Dawn surface handle (which - // can be null if surface creation failed). - replacedSurface = _nativeSurface; - replacedReleaser = std::move(_releaser); - _surface = std::move(_pendingSurface); - _nativeSurface = _pendingNativeSurface; - _releaser = std::move(_pendingReleaser); - _hasPendingAttach = false; - _pendingNativeSurface = nullptr; - _frameEpoch++; - - // _surface can be null here when Dawn surface creation failed for a - // valid native window; the context then just keeps rendering offscreen. - if (_config.device != nullptr && _surface) { - bool blit = _texture != nullptr; - // The blit needs CopyDst on the surface. Configure with a widened - // copy while keeping _config at the usage the user asked for, so any - // later reconfigure drops the extra flag again. - wgpu::SurfaceConfiguration config = _config; - if (blit) { - config.usage |= wgpu::TextureUsage::CopyDst; - } - _surface.Configure(&config); -#ifdef __APPLE__ - RNSkia::applyCAMetalLayerColorSpace(_nativeSurface, _config.format); -#endif - if (blit) { - presentBlit = blitOffscreenToSurfaceLocked(); - device = _config.device; - // Consumed either way; on failure the next frame renders fresh. - _texture = nullptr; - blitEpoch = _frameEpoch; - } - } - } - if (replacedReleaser && replacedSurface) { - replacedReleaser(replacedSurface); - } - if (presentBlit) { -#ifdef __APPLE__ - if (device) { - dawn::native::metal::WaitForCommandsToBeScheduled(device.Get()); - } -#endif - std::unique_lock lock(_mutex); - // Present only if the blitted texture is still the surface's current - // one. The epoch changes on any acquire, present, configure, detach, or - // adoption, so a frame that started - even one that already completed - - // or any other transition while we were unlocked skips this present - // (their newer content stands; presenting here would be a Dawn - // present-without-acquire error). - if (_surface && !_frameInFlight && _frameEpoch == blitEpoch) { - _surface.Present(); - } - } - } - - // --- Rendering thread - // ------------------------------------------------------- - - void configure(wgpu::SurfaceConfiguration &newConfig, - std::vector viewFormats) { - applyPendingAttach(/* supersedeInFlightFrame = */ true); - std::unique_lock lock(_mutex); - _viewFormats = std::move(viewFormats); - _config = newConfig; - // The caller's viewFormats storage dies with the call; point the stored - // configuration at our own copy. - _config.viewFormats = _viewFormats.empty() ? nullptr : _viewFormats.data(); - _config.viewFormatCount = _viewFormats.size(); - // The drawing buffer starts at the canvas size. Clamp so a canvas that has - // not been laid out yet (0x0) configures instead of erroring. - _config.width = std::max(1, _width); - _config.height = std::max(1, _height); - _config.presentMode = wgpu::PresentMode::Fifo; - _texture = nullptr; - _frameEpoch++; - _configureLocked(); - } - - // Resize the drawing buffer (canvas.width/height changed). - void reconfigure(int newWidth, int newHeight) { - std::unique_lock lock(_mutex); - if (_config.device == nullptr) { - return; - } - _config.width = std::max(1, newWidth); - _config.height = std::max(1, newHeight); - _texture = nullptr; - _frameEpoch++; - _configureLocked(); - } - - void unconfigure() { - std::unique_lock lock(_mutex); - if (_surface) { - _surface.Unconfigure(); - } - _texture = nullptr; - _config = {}; - _viewFormats.clear(); - _acquiredFromSurface = false; - _frameEpoch++; - } - - bool isConfigured() { - std::shared_lock lock(_mutex); - return _config.device != nullptr; - } - - // True while a native view owns a surface for this context (attached or - // pending adoption). Used to decide which side retires the registry entry: - // the native view's teardown when a surface exists, the JS Canvas cleanup - // otherwise (see RNWebGPU::destroyContext). - bool hasNativeSurface() { - std::shared_lock lock(_mutex); - return _nativeSurface != nullptr || _hasPendingAttach; - } - - // Returns the texture for the current frame: the surface's swapchain texture - // when a surface is attached and healthy, an offscreen texture otherwise. - // Never returns null; throws when called before configure(). - wgpu::Texture getCurrentTexture() { - // Start-of-frame boundary; a new acquire supersedes any previous frame - // that never presented. - applyPendingAttach(/* supersedeInFlightFrame = */ true); - std::unique_lock lock(_mutex); - if (_config.device == nullptr) { - throw std::runtime_error( - "[WebGPU] getCurrentTexture() called on a canvas context that is " - "not configured; call context.configure() first"); - } - _frameInFlight = true; - _acquiredFromSurface = false; - _frameEpoch++; - if (_surface) { - auto texture = acquireSurfaceTextureLocked(); - if (texture) { - _acquiredFromSurface = true; - return texture; - } - // The surface is transiently unusable (e.g. mid-resize, lost while - // backgrounding): fall back to an offscreen texture so the render loop - // survives; this frame is simply not presented. - } - if (!_texture) { - _texture = createOffscreenTextureLocked(); - } - return _texture; - } - - // Present the current frame. Runs synchronously on the thread that did - // getCurrentTexture/submit (main JS, Reanimated UI, or a worklet runtime), - // preserving Dawn surface thread-affinity. Frames whose texture was not - // acquired from the attached surface (offscreen, detached mid-frame, or - // acquire failure) are dropped. This is also the end-of-frame boundary: it - // adopts a surface that attached while the frame was in flight. - void presentFrame() { -#ifdef __APPLE__ - // Ensure command buffers are scheduled before presenting. Read the device - // under a shared lock, then wait without holding it (the wait can block). - wgpu::Device device; - { - std::shared_lock lock(_mutex); - device = _config.device; - } - if (device) { - dawn::native::metal::WaitForCommandsToBeScheduled(device.Get()); - } -#endif - { - std::unique_lock lock(_mutex); - if (_surface && _acquiredFromSurface) { - _surface.Present(); - } - _acquiredFromSurface = false; - _frameInFlight = false; - _frameEpoch++; - } - applyPendingAttach(); - } - - NativeInfo getNativeInfo() { - std::shared_lock lock(_mutex); - // A surface that is still pending adoption is the one callers should see. - void *native = _hasPendingAttach ? _pendingNativeSurface : _nativeSurface; - return {.nativeSurface = native, .width = _width, .height = _height}; - } - - Size getSize() { - std::shared_lock lock(_mutex); - return {.width = _width, .height = _height}; - } - - wgpu::SurfaceConfiguration getConfig() { - std::shared_lock lock(_mutex); - return _config; - } - -private: - void detach(bool createFallbackTexture) { - void *releasedSurfaces[2] = {nullptr, nullptr}; - NativeSurfaceReleaser releasers[2]; - { - std::unique_lock lock(_mutex); - // The platform is tearing surfaces down; a not-yet-adopted attach is - // stale, cancel it. - if (_hasPendingAttach) { - _hasPendingAttach = false; - _pendingSurface = nullptr; - releasedSurfaces[0] = _pendingNativeSurface; - releasers[0] = std::move(_pendingReleaser); - _pendingNativeSurface = nullptr; - } - if (_surface) { - if (createFallbackTexture && _config.device != nullptr) { - _texture = createOffscreenTextureLocked(); - } - _surface = nullptr; - // The in-flight frame (if any) rendered into the destroyed surface; - // presentFrame() must not present it. - _acquiredFromSurface = false; - } - _frameEpoch++; - // Window ownership is independent of the Dawn surface handle (which can - // be null if surface creation failed): always return the window. - releasedSurfaces[1] = _nativeSurface; - releasers[1] = std::move(_releaser); - _nativeSurface = nullptr; - } - // Release outside the lock: the platform may do real work here. - for (int i = 0; i < 2; i++) { - if (releasers[i] && releasedSurfaces[i]) { - releasers[i](releasedSurfaces[i]); - } - } - } - - // All *Locked helpers below require _mutex to be held exclusively. - - wgpu::Texture createOffscreenTextureLocked() { - wgpu::TextureDescriptor descriptor; - // Union with the user's usage so offscreen frames stay compatible with - // whatever they configured (e.g. CopySrc readbacks). RenderAttachment | - // CopySrc | TextureBinding is what the fallback itself needs (rendering, - // the attach blit, sampling). - descriptor.usage = _config.usage | wgpu::TextureUsage::RenderAttachment | - wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::TextureBinding; - descriptor.format = _config.format; - descriptor.size.width = std::max(1u, _config.width); - descriptor.size.height = std::max(1u, _config.height); - descriptor.viewFormats = _config.viewFormats; - descriptor.viewFormatCount = _config.viewFormatCount; - return _config.device.CreateTexture(&descriptor); - } - - // Acquire the surface's current texture, reconfiguring once when the surface - // reports it is stale (rotation, resize, coming back from background). - wgpu::Texture acquireSurfaceTextureLocked() { - wgpu::SurfaceTexture surfaceTexture; - _surface.GetCurrentTexture(&surfaceTexture); - if (!isAcquireSuccess(surfaceTexture)) { - if (surfaceTexture.status == - wgpu::SurfaceGetCurrentTextureStatus::Error) { - return nullptr; - } - _surface.Configure(&_config); - _surface.GetCurrentTexture(&surfaceTexture); - if (!isAcquireSuccess(surfaceTexture)) { - return nullptr; - } - } - return surfaceTexture.texture; - } - - static bool isAcquireSuccess(const wgpu::SurfaceTexture &surfaceTexture) { - return (surfaceTexture.status == - wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal || - surfaceTexture.status == - wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal) && - surfaceTexture.texture != nullptr; - } - - // Copy the last offscreen frame onto the freshly attached surface. Returns - // true when the copy was submitted and the surface should be presented. - bool blitOffscreenToSurfaceLocked() { - wgpu::SurfaceTexture surfaceTexture; - _surface.GetCurrentTexture(&surfaceTexture); - if (!isAcquireSuccess(surfaceTexture)) { - return false; - } - - wgpu::TexelCopyTextureInfo source = {}; - source.texture = _texture; - wgpu::TexelCopyTextureInfo destination = {}; - destination.texture = surfaceTexture.texture; - - // The offscreen frame and the new surface can disagree on size (e.g. the - // device rotated while detached); copy the shared region. - wgpu::Extent3D size = { - std::min(_texture.GetWidth(), surfaceTexture.texture.GetWidth()), - std::min(_texture.GetHeight(), surfaceTexture.texture.GetHeight()), 1}; - - wgpu::CommandEncoderDescriptor encoderDescriptor; - wgpu::CommandEncoder encoder = - _config.device.CreateCommandEncoder(&encoderDescriptor); - encoder.CopyTextureToTexture(&source, &destination, &size); - wgpu::CommandBuffer commands = encoder.Finish(); - _config.device.GetQueue().Submit(1, &commands); - return true; - } - - void _configureLocked() { - if (_surface) { - _surface.Configure(&_config); -#ifdef __APPLE__ - RNSkia::applyCAMetalLayerColorSpace(_nativeSurface, _config.format); -#endif - } else { - _texture = createOffscreenTextureLocked(); - } - } - - mutable std::shared_mutex _mutex; - // Attached on-screen surface (null while offscreen). - void *_nativeSurface = nullptr; - wgpu::Surface _surface = nullptr; - NativeSurfaceReleaser _releaser; - // Offscreen fallback drawing buffer. - wgpu::Texture _texture = nullptr; - // Surface attached by the UI thread, awaiting adoption at a frame boundary. - bool _hasPendingAttach = false; - void *_pendingNativeSurface = nullptr; - wgpu::Surface _pendingSurface = nullptr; - NativeSurfaceReleaser _pendingReleaser; - // Frame state: set by getCurrentTexture, cleared by presentFrame. - bool _frameInFlight = false; - bool _acquiredFromSurface = false; - // Bumped on every acquire, present, configure/reconfigure/unconfigure, - // adoption, and detach. The deferred blit-present in applyPendingAttach - // revalidates against it so it never presents a texture that stopped being - // the surface's current one while the lock was released. - uint64_t _frameEpoch = 0; - // device == nullptr means "not configured". _viewFormats owns the storage - // that _config.viewFormats points at. - wgpu::SurfaceConfiguration _config; - std::vector _viewFormats; - // Keeps the Dawn instance alive for as long as any canvas exists. - wgpu::Instance _gpu; - // Native view size in dp (surfaced as clientWidth/clientHeight on the JS - // canvas). - int _width; - int _height; -}; - -class SurfaceRegistry { -public: - static SurfaceRegistry &getInstance() { - static SurfaceRegistry instance; - return instance; - } - - SurfaceRegistry(const SurfaceRegistry &) = delete; - SurfaceRegistry &operator=(const SurfaceRegistry &) = delete; - - std::shared_ptr getSurfaceInfo(int id) { - std::shared_lock lock(_mutex); - auto it = _registry.find(id); - if (it != _registry.end()) { - return it->second; - } - return nullptr; - } - - void removeSurfaceInfo(int id) { - std::unique_lock lock(_mutex); - _registry.erase(id); - } - - std::shared_ptr - getSurfaceInfoOrCreate(int id, wgpu::Instance gpu, int width, int height) { - std::unique_lock lock(_mutex); - return getSurfaceInfoOrCreateLocked(id, gpu, width, height); - } - - // Find-or-create + attach as one atomic step under the registry lock, so it - // serializes with removeSurfaceInfoIfDetached: an attach can never land on - // an entry that a concurrent destroyContext is erasing (it either marks the - // entry attached before the check, or re-creates the entry after the - // erase). Lock order is registry -> SurfaceInfo, matching every other path. - std::shared_ptr attachSurface(int id, wgpu::Instance gpu, - int width, int height, - void *nativeSurface, - wgpu::Surface surface, - NativeSurfaceReleaser releaser) { - std::unique_lock lock(_mutex); - auto info = getSurfaceInfoOrCreateLocked(id, gpu, width, height); - info->attachSurface(nativeSurface, std::move(surface), std::move(releaser)); - return info; - } - - // Erase the entry only if no native surface is attached or pending; the - // atomic counterpart of attachSurface above (see RNWebGPU::destroyContext - // for the ownership split this implements). - void removeSurfaceInfoIfDetached(int id) { - std::unique_lock lock(_mutex); - auto it = _registry.find(id); - if (it == _registry.end() || it->second->hasNativeSurface()) { - return; - } - _registry.erase(it); - } - - // Drops all entries. Called when the RN instance tears down (dev reload): - // JS context ids restart from scratch, so surviving entries would alias new - // canvases onto dead surfaces. - void clear() { - std::unique_lock lock(_mutex); - _registry.clear(); - } - -private: - SurfaceRegistry() = default; - - std::shared_ptr getSurfaceInfoOrCreateLocked(int id, - wgpu::Instance gpu, - int width, - int height) { - auto it = _registry.find(id); - if (it != _registry.end()) { - return it->second; - } - auto info = std::make_shared(gpu, width, height); - _registry[id] = info; - return info; - } - - mutable std::shared_mutex _mutex; - std::unordered_map> _registry; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/AppleNativeBuffer.h b/packages/skia/cpp/rnwgpu/api/AppleNativeBuffer.h deleted file mode 100644 index 0393707503..0000000000 --- a/packages/skia/cpp/rnwgpu/api/AppleNativeBuffer.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#if defined(__APPLE__) - -#include - -namespace rnwgpu { - -// Extract the backing IOSurface and dimensions from a CVPixelBufferRef pointer -// (the value Skia's NativeBuffer.MakeFromImage returns on Apple). The returned -// IOSurfaceRef is owned by the CVPixelBuffer; the caller must keep the -// CVPixelBuffer alive while the IOSurface is in use. Returns nullptr (and -// leaves the out-params at 0) if the buffer has no IOSurface. -// -// Defined in apple/RNWebGPUAppleNativeBuffer.mm (Objective-C++ so it can use -// CoreVideo, which isn't available from the cpp/ translation units). -void *GetIOSurfaceFromNativeBuffer(void *cvPixelBuffer, uint32_t *outWidth, - uint32_t *outHeight); - -} // namespace rnwgpu - -#endif // __APPLE__ diff --git a/packages/skia/cpp/rnwgpu/api/Convertors.h b/packages/skia/cpp/rnwgpu/api/Convertors.h deleted file mode 100644 index 33a6d692d6..0000000000 --- a/packages/skia/cpp/rnwgpu/api/Convertors.h +++ /dev/null @@ -1,783 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "descriptors/GPUBindGroupDescriptor.h" -#include "descriptors/GPUBindGroupEntry.h" -#include "descriptors/GPUBindGroupLayoutDescriptor.h" -#include "descriptors/GPUBindGroupLayoutEntry.h" -#include "descriptors/GPUBlendComponent.h" -#include "descriptors/GPUBlendState.h" -#include "descriptors/GPUBufferBinding.h" -#include "descriptors/GPUBufferBindingLayout.h" -#include "descriptors/GPUBufferDescriptor.h" -#include "descriptors/GPUColor.h" -#include "descriptors/GPUColorTargetState.h" -#include "descriptors/GPUCommandBufferDescriptor.h" -#include "descriptors/GPUCommandEncoderDescriptor.h" -#include "descriptors/GPUComputePassDescriptor.h" -#include "descriptors/GPUComputePassTimestampWrites.h" -#include "descriptors/GPUComputePipelineDescriptor.h" -#include "descriptors/GPUDepthStencilState.h" -#include "descriptors/GPUDeviceDescriptor.h" -#include "descriptors/GPUExternalTextureBindingLayout.h" -#include "descriptors/GPUFragmentState.h" -#include "descriptors/GPUImageCopyBuffer.h" -#include "descriptors/GPUImageCopyTexture.h" -#include "descriptors/GPUImageCopyTextureTagged.h" -#include "descriptors/GPUImageDataLayout.h" -#include "descriptors/GPUMultisampleState.h" -#include "descriptors/GPUPipelineLayoutDescriptor.h" -#include "descriptors/GPUPrimitiveState.h" -#include "descriptors/GPUProgrammableStage.h" -#include "descriptors/GPUQuerySetDescriptor.h" -#include "descriptors/GPUQueueDescriptor.h" -#include "descriptors/GPURenderBundleDescriptor.h" -#include "descriptors/GPURenderBundleEncoderDescriptor.h" -#include "descriptors/GPURenderPassColorAttachment.h" -#include "descriptors/GPURenderPassDepthStencilAttachment.h" -#include "descriptors/GPURenderPassDescriptor.h" -#include "descriptors/GPURenderPassTimestampWrites.h" -#include "descriptors/GPURenderPipelineDescriptor.h" -#include "descriptors/GPURequestAdapterOptions.h" -#include "descriptors/GPUSamplerBindingLayout.h" -#include "descriptors/GPUSamplerDescriptor.h" -#include "descriptors/GPUShaderModuleCompilationHint.h" -#include "descriptors/GPUShaderModuleDescriptor.h" -#include "descriptors/GPUStencilFaceState.h" -#include "descriptors/GPUStorageTextureBindingLayout.h" -#include "descriptors/GPUTextureBindingLayout.h" -#include "descriptors/GPUTextureDescriptor.h" -#include "descriptors/GPUTextureViewDescriptor.h" -#include "descriptors/GPUVertexAttribute.h" -#include "descriptors/GPUVertexBufferLayout.h" -#include "descriptors/GPUVertexState.h" -#include "descriptors/Unions.h" - -namespace rnwgpu { - -class Convertor { -public: - ~Convertor() { - for (auto &free : free_) { - free(); - } - } - - template - [[nodiscard]] inline bool operator()(OUT &&out, IN &&in) { - return Convert(std::forward(out), std::forward(in)); - } - - template - [[nodiscard]] inline bool operator()(OUT *&out_els, size_t &out_count, - const std::vector &in) { - return Convert(out_els, out_count, in); - } - - template - [[nodiscard]] inline bool Convert(OUT *&out_els, size_t &out_count, - const std::optional> &in) { - if (!in.has_value()) { - out_els = nullptr; - out_count = 0; - return true; - } - return Convert(out_els, out_count, in.value()); - } - - template - [[nodiscard]] inline bool Convert(OUT *&out_els, size_t &out_count, - const std::vector &in) { - if (in.size() == 0) { - out_els = nullptr; - out_count = 0; - return true; - } - auto *els = Allocate>(in.size()); - for (size_t i = 0; i < in.size(); i++) { - if (!Convert(els[i], in[i])) { - return false; - } - } - out_els = els; - return Convert(out_count, in.size()); - } - - template - [[nodiscard]] inline bool - Convert(OUT *&out_els, size_t &out_count, - const std::vector> &in) { - std::vector filtered; - filtered.reserve(in.size()); - - for (const auto &item : in) { - if (auto ptr = std::get_if(&item)) { - filtered.push_back(*ptr); - } - } - - return Convert(out_els, out_count, filtered); - } - - template - [[nodiscard]] inline bool - Convert(OUT *&out_els, size_t &out_count, - const std::optional> &in) { - if (!in.has_value() || in.value().size() == 0) { - out_els = nullptr; - out_count = 0; - return true; - } - auto val = in.value(); - auto *els = Allocate>(val.size()); - size_t i = 0; - for (const auto &item : val) { - if (!Convert(els[i], item.first, item.second)) { - return false; - } - i++; - } - out_els = els; - return Convert(out_count, val.size()); - } - - template - [[nodiscard]] auto Convert(T &out, const std::nullptr_t &in) { - out = nullptr; - return true; - } - - [[nodiscard]] bool Convert(wgpu::Bool &out, const bool &in) { - out = in; - return true; - } - - template - [[nodiscard]] typename std::enable_if< - (std::is_arithmetic::value || std::is_enum::value), bool>::type - Convert(T &out, const double &in) { - out = static_cast(in); - return true; - } - - template - [[nodiscard]] typename std::enable_if::value, bool>::type - Convert(T &out, const T &in) { - out = in; - return true; - } - - [[nodiscard]] bool Convert(wgpu::OptionalBool &out, - const std::optional &in) { - out = in; - return true; - } - - [[nodiscard]] bool Convert(wgpu::StringView &out, const std::string &in) { - out = {in.data(), in.size()}; - return true; - } - - [[nodiscard]] bool Convert(const char *&out, const std::string &in) { - out = in.c_str(); - return true; - } - - template - [[nodiscard]] bool Convert(OUT &out, const std::optional &in) { - if (in.has_value()) { - return Convert(out, in.value()); - } - return true; - } - - template - struct has_get_member : std::false_type {}; - - template - struct has_get_member().get())>> - : std::true_type {}; - - template - [[nodiscard]] bool Convert(OUT &out, const std::shared_ptr &in) { - if constexpr (has_get_member::value) { - out = in->get(); - return true; - } else { - return Convert(out, *in); - } - } - - template >> - [[nodiscard]] inline bool Convert(OUT *&out, const std::optional &in) { - if (in.has_value()) { - auto *el = Allocate>(); - if (!Convert(*el, in.value())) { - return false; - } - out = el; - } else { - out = nullptr; - } - return true; - } - - template - [[nodiscard]] bool Convert(OUT &out, - const std::variant &in) { - if (std::holds_alternative(in)) { - return Convert(out, std::get(in)); - } - return Convert(out, std::get(in)); - } - - [[nodiscard]] bool Convert(wgpu::Origin3D &out, const GPUOrigin3D &in) { - return Convert(out.x, in.x) && Convert(out.y, in.y) && Convert(out.z, in.z); - } - - [[nodiscard]] bool Convert(wgpu::Extent3D &out, const GPUExtent3D &in) { - return Convert(out.width, in.width) && Convert(out.height, in.height) && - Convert(out.depthOrArrayLayers, in.depthOrArrayLayers); - } - - [[nodiscard]] bool Convert(wgpu::BindGroupLayoutEntry &out, - const GPUBindGroupLayoutEntry &in) { - out = {}; - if (!Convert(out.binding, in.binding) || - !Convert(out.visibility, in.visibility) || - !Convert(out.buffer, in.buffer) || !Convert(out.sampler, in.sampler) || - !Convert(out.texture, in.texture) || - !Convert(out.storageTexture, in.storageTexture)) { - return false; - } - if (in.externalTexture.has_value() && - in.externalTexture.value() != nullptr) { - // External texture layouts bind via a chained struct rather than a - // direct field on BindGroupLayoutEntry. The chained struct must outlive - // the BindGroupLayoutEntry until Device::CreateBindGroupLayout returns, - // so we allocate it on the Convertor's arena. - auto *chain = Allocate(); - out.nextInChain = chain; - } - return true; - } - - [[nodiscard]] bool Convert(wgpu::BlendComponent &out, - const GPUBlendComponent &in) { - out = {}; - return Convert(out.operation, in.operation) && - Convert(out.dstFactor, in.dstFactor) && - Convert(out.srcFactor, in.srcFactor); - } - - [[nodiscard]] bool Convert(wgpu::BlendState &out, const GPUBlendState &in) { - out = {}; - return Convert(out.alpha, in.alpha) && Convert(out.color, in.color); - } - - [[nodiscard]] bool Convert(wgpu::BufferBindingLayout &out, - const GPUBufferBindingLayout &in) { - // here the buffer property is set so type is set to its default value - if (!in.type.has_value()) { - out.type = wgpu::BufferBindingType::Uniform; - } - return Convert(out.type, in.type) && - Convert(out.hasDynamicOffset, in.hasDynamicOffset) && - Convert(out.minBindingSize, in.minBindingSize); - } - - [[nodiscard]] bool Convert(wgpu::BufferDescriptor &out, - const GPUBufferDescriptor &in) { - return Convert(out.size, in.size) && Convert(out.usage, in.usage) && - Convert(out.mappedAtCreation, in.mappedAtCreation) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::Color &out, const GPUColor &in) { - return Convert(out.r, in.r) && Convert(out.g, in.g) && - Convert(out.b, in.b) && Convert(out.a, in.a); - } - - [[nodiscard]] bool Convert(wgpu::ColorTargetState &out, - const GPUColorTargetState &in) { - out = {}; - return Convert(out.blend, in.blend) && Convert(out.format, in.format) && - Convert(out.writeMask, in.writeMask); - } - - [[nodiscard]] bool Convert(wgpu::ComputePassDescriptor &out, - const GPUComputePassDescriptor &in) { - return Convert(out.timestampWrites, in.timestampWrites) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::PassTimestampWrites &out, - const GPUComputePassTimestampWrites &in) { - return Convert(out.querySet, in.querySet) && - Convert(out.beginningOfPassWriteIndex, - in.beginningOfPassWriteIndex) && - Convert(out.endOfPassWriteIndex, in.endOfPassWriteIndex); - } - - [[nodiscard]] bool Convert(wgpu::ComputePipelineDescriptor &out, - const GPUComputePipelineDescriptor &in) { - return Convert(out.compute, in.compute) && Convert(out.layout, in.layout) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::DepthStencilState &out, - const GPUDepthStencilState &in) { - return Convert(out.format, in.format) && - Convert(out.depthWriteEnabled, in.depthWriteEnabled) && - Convert(out.depthCompare, in.depthCompare) && - Convert(out.stencilFront, in.stencilFront) && - Convert(out.stencilBack, in.stencilBack) && - Convert(out.stencilReadMask, in.stencilReadMask) && - Convert(out.stencilWriteMask, in.stencilWriteMask) && - Convert(out.depthBias, in.depthBias) && - Convert(out.depthBiasSlopeScale, in.depthBiasSlopeScale) && - Convert(out.depthBiasClamp, in.depthBiasClamp); - } - - [[nodiscard]] bool Convert(wgpu::DeviceDescriptor &out, - const GPUDeviceDescriptor &in) { - if (in.requiredFeatures.has_value()) { - if (!Convert(out.requiredFeatures, out.requiredFeatureCount, - in.requiredFeatures.value())) { - return false; - } - } - - if (in.requiredLimits.has_value()) { - const auto &limits = in.requiredLimits.value(); - auto *requiredLimits = Allocate(); - for (const auto &[key, value] : limits) { - if (key == "maxTextureDimension1D") { - requiredLimits->maxTextureDimension1D = value; - } else if (key == "maxTextureDimension2D") { - requiredLimits->maxTextureDimension2D = value; - } else if (key == "maxTextureDimension3D") { - requiredLimits->maxTextureDimension3D = value; - } else if (key == "maxTextureArrayLayers") { - requiredLimits->maxTextureArrayLayers = value; - } else if (key == "maxBindGroups") { - requiredLimits->maxBindGroups = value; - } else if (key == "maxBindGroupsPlusVertexBuffers") { - requiredLimits->maxBindGroupsPlusVertexBuffers = value; - } else if (key == "maxBindingsPerBindGroup") { - requiredLimits->maxBindingsPerBindGroup = value; - } else if (key == "maxDynamicUniformBuffersPerPipelineLayout") { - requiredLimits->maxDynamicUniformBuffersPerPipelineLayout = value; - } else if (key == "maxDynamicStorageBuffersPerPipelineLayout") { - requiredLimits->maxDynamicStorageBuffersPerPipelineLayout = value; - } else if (key == "maxSampledTexturesPerShaderStage") { - requiredLimits->maxSampledTexturesPerShaderStage = value; - } else if (key == "maxSamplersPerShaderStage") { - requiredLimits->maxSamplersPerShaderStage = value; - } else if (key == "maxStorageBuffersPerShaderStage") { - requiredLimits->maxStorageBuffersPerShaderStage = value; - } else if (key == "maxStorageTexturesPerShaderStage") { - requiredLimits->maxStorageTexturesPerShaderStage = value; - } else if (key == "maxUniformBuffersPerShaderStage") { - requiredLimits->maxUniformBuffersPerShaderStage = value; - } else if (key == "maxUniformBufferBindingSize") { - requiredLimits->maxUniformBufferBindingSize = value; - } else if (key == "maxStorageBufferBindingSize") { - requiredLimits->maxStorageBufferBindingSize = value; - } else if (key == "minUniformBufferOffsetAlignment") { - requiredLimits->minUniformBufferOffsetAlignment = value; - } else if (key == "minStorageBufferOffsetAlignment") { - requiredLimits->minStorageBufferOffsetAlignment = value; - } else if (key == "maxVertexBuffers") { - requiredLimits->maxVertexBuffers = value; - } else if (key == "maxBufferSize") { - requiredLimits->maxBufferSize = value; - } else if (key == "maxVertexAttributes") { - requiredLimits->maxVertexAttributes = value; - } else if (key == "maxVertexBufferArrayStride") { - requiredLimits->maxVertexBufferArrayStride = value; - } else if (key == "maxInterStageShaderVariables") { - requiredLimits->maxInterStageShaderVariables = value; - } else if (key == "maxColorAttachments") { - requiredLimits->maxColorAttachments = value; - } else if (key == "maxColorAttachmentBytesPerSample") { - requiredLimits->maxColorAttachmentBytesPerSample = value; - } else if (key == "maxComputeWorkgroupStorageSize") { - requiredLimits->maxComputeWorkgroupStorageSize = value; - } else if (key == "maxComputeInvocationsPerWorkgroup") { - requiredLimits->maxComputeInvocationsPerWorkgroup = value; - } else if (key == "maxComputeWorkgroupSizeX") { - requiredLimits->maxComputeWorkgroupSizeX = value; - } else if (key == "maxComputeWorkgroupSizeY") { - requiredLimits->maxComputeWorkgroupSizeY = value; - } else if (key == "maxComputeWorkgroupSizeZ") { - requiredLimits->maxComputeWorkgroupSizeZ = value; - } else if (key == "maxComputeWorkgroupsPerDimension") { - requiredLimits->maxComputeWorkgroupsPerDimension = value; - } - } - out.requiredLimits = requiredLimits; - } - return Convert(out.defaultQueue, in.defaultQueue) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::ExternalTextureBindingLayout &out, - const GPUExternalTextureBindingLayout & /*in*/) { - // ExternalTextureBindingLayout carries no fields of its own; its presence - // (as a chained struct) is what marks the entry as an external texture. - out = {}; - return true; - } - - [[nodiscard]] bool Convert(wgpu::ConstantEntry &out, const std::string &key, - const double &value) { - out.key = ConvertStringReplacingNull(key); - out.value = value; - return true; - } - - [[nodiscard]] bool Convert(wgpu::FragmentState &out, - const GPUFragmentState &in) { - out = {}; - - // Replace nulls in the entryPoint name with another character that's - // disallowed in WGSL identifiers. This is so that using "main\0" doesn't - // match an entryPoint named "main". - out.entryPoint = in.entryPoint - ? ConvertStringReplacingNull(in.entryPoint.value()) - : nullptr; - return Convert(out.targets, out.targetCount, in.targets) && // - Convert(out.module, in.module) && - Convert(out.constants, out.constantCount, in.constants); - } - - [[nodiscard]] bool Convert(wgpu::TexelCopyBufferInfo &out, - const GPUImageCopyBuffer &in) { - out = {}; - out.buffer = in.buffer->get(); - return Convert(out.layout.offset, in.offset) && - Convert(out.layout.bytesPerRow, in.bytesPerRow) && - Convert(out.layout.rowsPerImage, in.rowsPerImage); - } - - [[nodiscard]] bool Convert(wgpu::TexelCopyTextureInfo &out, - const GPUImageCopyTexture &in) { - return Convert(out.origin, in.origin) && Convert(out.texture, in.texture) && - Convert(out.mipLevel, in.mipLevel) && Convert(out.aspect, in.aspect); - } - - [[nodiscard]] bool Convert(wgpu::TexelCopyBufferLayout &out, - const GPUImageDataLayout &in) { - out = {}; - return Convert(out.bytesPerRow, in.bytesPerRow) && - Convert(out.offset, in.offset) && - Convert(out.rowsPerImage, in.rowsPerImage); - } - - [[nodiscard]] bool Convert(wgpu::MultisampleState &out, - const GPUMultisampleState &in) { - return Convert(out.count, in.count) && Convert(out.mask, in.mask) && - Convert(out.alphaToCoverageEnabled, in.alphaToCoverageEnabled); - } - - [[nodiscard]] bool Convert(wgpu::PipelineLayoutDescriptor &out, - const GPUPipelineLayoutDescriptor &in) { - return Convert(out.bindGroupLayouts, out.bindGroupLayoutCount, - in.bindGroupLayouts) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::PrimitiveState &out, - const GPUPrimitiveState &in) { - out = {}; - - if (in.unclippedDepth.has_value()) { - out.unclippedDepth = in.unclippedDepth.value(); - } - - return Convert(out.topology, in.topology) && - Convert(out.stripIndexFormat, in.stripIndexFormat) && - Convert(out.frontFace, in.frontFace) && - Convert(out.cullMode, in.cullMode); - } - - [[nodiscard]] bool Convert(wgpu::ComputeState &out, - const GPUProgrammableStage &in) { - out = {}; - out.module = in.module->get(); - - // Replace nulls in the entryPoint name with another character that's - // disallowed in WGSL identifiers. This is so that using "main\0" doesn't - // match an entryPoint named "main". - out.entryPoint = in.entryPoint - ? ConvertStringReplacingNull(in.entryPoint.value()) - : nullptr; - return Convert(out.constants, out.constantCount, in.constants); - } - - [[nodiscard]] bool Convert(wgpu::QuerySetDescriptor &out, - const GPUQuerySetDescriptor &in) { - return Convert(out.type, in.type) && Convert(out.count, in.count) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::RenderBundleEncoderDescriptor &out, - const GPURenderBundleEncoderDescriptor &in) { - return Convert(out.depthReadOnly, in.depthReadOnly) && - Convert(out.stencilReadOnly, in.stencilReadOnly) && - Convert(out.colorFormats, out.colorFormatCount, in.colorFormats) && - Convert(out.depthStencilFormat, in.depthStencilFormat) && - Convert(out.sampleCount, in.sampleCount) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::RenderPassColorAttachment &out, - const GPURenderPassColorAttachment &in) { - return Convert(out.view, in.view) && - Convert(out.depthSlice, in.depthSlice) && - Convert(out.resolveTarget, in.resolveTarget) && - Convert(out.clearValue, in.clearValue) && - Convert(out.loadOp, in.loadOp) && Convert(out.storeOp, in.storeOp); - } - - [[nodiscard]] bool Convert(wgpu::RenderPassDepthStencilAttachment &out, - const GPURenderPassDepthStencilAttachment &in) { - return Convert(out.view, in.view) && - Convert(out.depthClearValue, in.depthClearValue) && - Convert(out.depthLoadOp, in.depthLoadOp) && - Convert(out.depthStoreOp, in.depthStoreOp) && - Convert(out.depthReadOnly, in.depthReadOnly) && - Convert(out.stencilClearValue, in.stencilClearValue) && - Convert(out.stencilLoadOp, in.stencilLoadOp) && - Convert(out.stencilStoreOp, in.stencilStoreOp) && - Convert(out.stencilReadOnly, in.stencilReadOnly); - } - - [[nodiscard]] bool Convert(wgpu::PassTimestampWrites &out, - const GPURenderPassTimestampWrites &in) { - return Convert(out.querySet, in.querySet) && - Convert(out.beginningOfPassWriteIndex, - in.beginningOfPassWriteIndex) && - Convert(out.endOfPassWriteIndex, in.endOfPassWriteIndex); - } - - [[nodiscard]] bool Convert(wgpu::RenderPipelineDescriptor &out, - const GPURenderPipelineDescriptor &in) { - return Convert(out.vertex, in.vertex) && - Convert(out.primitive, in.primitive) && - Convert(out.depthStencil, in.depthStencil) && - Convert(out.multisample, in.multisample) && - Convert(out.fragment, in.fragment) && - Convert(out.layout, in.layout) && Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::RequestAdapterOptions &out, - const GPURequestAdapterOptions &in) { - return Convert(out.powerPreference, in.powerPreference) && - Convert(out.forceFallbackAdapter, in.forceFallbackAdapter); - } - - [[nodiscard]] bool Convert(wgpu::SamplerBindingLayout &out, - const GPUSamplerBindingLayout &in) { - // here the buffer property is set so type is set to its default value - if (!in.type.has_value()) { - out.type = wgpu::SamplerBindingType::Filtering; - } - return Convert(out.type, in.type); - } - - [[nodiscard]] bool Convert(wgpu::SamplerDescriptor &out, - const GPUSamplerDescriptor &in) { - return Convert(out.addressModeU, in.addressModeU) && - Convert(out.addressModeV, in.addressModeV) && - Convert(out.addressModeW, in.addressModeW) && - Convert(out.magFilter, in.magFilter) && - Convert(out.minFilter, in.minFilter) && - Convert(out.mipmapFilter, in.mipmapFilter) && - Convert(out.lodMinClamp, in.lodMinClamp) && - Convert(out.lodMaxClamp, in.lodMaxClamp) && - Convert(out.compare, in.compare) && - Convert(out.maxAnisotropy, in.maxAnisotropy) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::StencilFaceState &out, - const GPUStencilFaceState &in) { - return Convert(out.compare, in.compare) && Convert(out.failOp, in.failOp) && - Convert(out.depthFailOp, in.depthFailOp) && - Convert(out.passOp, in.passOp); - } - - [[nodiscard]] bool Convert(wgpu::StorageTextureBindingLayout &out, - const GPUStorageTextureBindingLayout &in) { - if (!in.access.has_value()) { - out.access = wgpu::StorageTextureAccess::WriteOnly; - } - return Convert(out.access, in.access) && Convert(out.format, in.format) && - Convert(out.viewDimension, in.viewDimension); - } - - [[nodiscard]] bool Convert(wgpu::TextureBindingLayout &out, - const GPUTextureBindingLayout &in) { - if (!in.sampleType.has_value()) { - out.sampleType = wgpu::TextureSampleType::Float; - } - return Convert(out.sampleType, in.sampleType) && - Convert(out.viewDimension, in.viewDimension) && - Convert(out.multisampled, in.multisampled); - } - - [[nodiscard]] bool Convert(wgpu::TextureDescriptor &out, - const GPUTextureDescriptor &in) { - if (in.viewFormats.has_value()) { - if (!Convert(out.viewFormats, out.viewFormatCount, - in.viewFormats.value())) { - return false; - } - } - return Convert(out.size, in.size) && - Convert(out.mipLevelCount, in.mipLevelCount) && - Convert(out.sampleCount, in.sampleCount) && - Convert(out.dimension, in.dimension) && - Convert(out.format, in.format) && Convert(out.usage, in.usage) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::TextureViewDescriptor &out, - const GPUTextureViewDescriptor &in) { - return Convert(out.format, in.format) && - Convert(out.dimension, in.dimension) && - Convert(out.aspect, in.aspect) && - Convert(out.baseMipLevel, in.baseMipLevel) && - Convert(out.mipLevelCount, in.mipLevelCount) && - Convert(out.baseArrayLayer, in.baseArrayLayer) && - Convert(out.arrayLayerCount, in.arrayLayerCount) && - Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::VertexAttribute &out, - const GPUVertexAttribute &in) { - return Convert(out.format, in.format) && Convert(out.offset, in.offset) && - Convert(out.shaderLocation, in.shaderLocation); - } - - [[nodiscard]] bool Convert(wgpu::VertexBufferLayout &out, - const GPUVertexBufferLayout &in) { - out = {}; - /* - TODO: - - if (in.stepMode == wgpu::VertexStepMode::VertexBufferNotUsed) { - - return Convert(out.stepMode, in.stepMode); - - } - */ - return Convert(out.attributes, out.attributeCount, in.attributes) && - Convert(out.arrayStride, in.arrayStride) && - Convert(out.stepMode, in.stepMode); - } - - [[nodiscard]] bool Convert(wgpu::VertexState &out, const GPUVertexState &in) { - out = {}; - // Replace nulls in the entryPoint name with another character that's - // disallowed in WGSL identifiers. This is so that using "main\0" doesn't - // match an entryPoint named "main". - out.entryPoint = in.entryPoint - ? ConvertStringReplacingNull(in.entryPoint.value()) - : nullptr; - return Convert(out.module, in.module) && - Convert(out.buffers, out.bufferCount, in.buffers) && - Convert(out.constants, out.constantCount, in.constants); - } - - [[nodiscard]] bool Convert(wgpu::CommandBufferDescriptor &out, - const GPUCommandBufferDescriptor &in) { - return Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::CommandEncoderDescriptor &out, - const GPUCommandEncoderDescriptor &in) { - return Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::QueueDescriptor &out, - const GPUQueueDescriptor &in) { - return Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::RenderBundleDescriptor &out, - const GPURenderBundleDescriptor &in) { - return Convert(out.label, in.label); - } - - [[nodiscard]] bool Convert(wgpu::BindGroupEntry &out, - const GPUBindGroupEntry &in) { - out = {}; - if (!Convert(out.binding, in.binding)) { - return false; - } - - if (in.sampler != nullptr) { - return Convert(out.sampler, in.sampler); - } - if (in.textureView != nullptr) { - return Convert(out.textureView, in.textureView); - } - if (in.buffer != nullptr) { - auto buffer = in.buffer->buffer; - out.size = wgpu::kWholeSize; - if (!buffer || !Convert(out.offset, in.buffer->offset) || - !Convert(out.size, in.buffer->size)) { - return false; - } - out.buffer = buffer->get(); - return true; - } - if (in.externalTexture != nullptr) { - // External textures bind via a chained struct rather than a direct field - // on BindGroupEntry. The chained struct must outlive the BindGroupEntry - // until Device::CreateBindGroup returns, so we allocate it on the - // Convertor's arena. - auto *chain = Allocate(); - chain->externalTexture = in.externalTexture->get(); - out.nextInChain = chain; - return true; - } - return false; - } - -private: - char *ConvertStringReplacingNull(std::string_view in) { - char *out = Allocate(in.size() + 1); - out[in.size()] = '\0'; - - for (size_t i = 0; i < in.size(); i++) { - if (in[i] == '\0') { - out[i] = '#'; - } else { - out[i] = in[i]; - } - } - - return out; - } - - template T *Allocate(size_t n = 1) { - auto *ptr = new T[n]{}; - free_.emplace_back([ptr] { delete[] ptr; }); - return ptr; - } - - std::vector> free_; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/External.h b/packages/skia/cpp/rnwgpu/api/External.h deleted file mode 100644 index 154bab90d1..0000000000 --- a/packages/skia/cpp/rnwgpu/api/External.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { -enum class PredefinedColorSpace : uint32_t { - DisplayP3 = 0, - Srgb = 1, -}; - -enum class PremultiplyAlpha : uint32_t { Default = 0, None = 1, Premultiply }; -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPU.cpp b/packages/skia/cpp/rnwgpu/api/GPU.cpp deleted file mode 100644 index 59ff840235..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPU.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "GPU.h" - -#include -#include -#include -#include -#include -#include - -#include "Convertors.h" -#include "jsi/JSIConverter.h" -#include "rnwgpu/async/RuntimeContext.h" - -namespace rnwgpu { - -GPU::GPU(jsi::Runtime & /*runtime*/, wgpu::Instance instance) - : NativeObject(CLASS_NAME), _instance(instance) {} - -async::AsyncTaskHandle GPU::requestAdapter( - jsi::Runtime &runtime, - std::optional> options) { - wgpu::RequestAdapterOptions aOptions; - Convertor conv; - if (!conv(aOptions, options)) { - throw std::runtime_error("Failed to convert GPUDeviceDescriptor"); - } -#ifdef __APPLE__ - constexpr auto kDefaultBackendType = wgpu::BackendType::Metal; -#else - constexpr auto kDefaultBackendType = wgpu::BackendType::Vulkan; -#endif - aOptions.backendType = kDefaultBackendType; - - // Per-runtime context: async ops requested on this runtime resolve on this - // runtime's own thread (via its ProcessEvents pump). - auto context = async::RuntimeContext::getOrCreate(runtime, _instance); - return context->postTask( - [this, aOptions, - context](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { - _instance.RequestAdapter( - &aOptions, wgpu::CallbackMode::AllowProcessEvents, - [context, resolve, reject](wgpu::RequestAdapterStatus status, - wgpu::Adapter adapter, - wgpu::StringView message) { - if (message.length) { - fprintf(stderr, "%s", message.data); - } - - if (status == wgpu::RequestAdapterStatus::Success && adapter) { - auto adapterHost = - std::make_shared(std::move(adapter), context); - auto result = - std::variant>( - adapterHost); - resolve([result = - std::move(result)](jsi::Runtime &runtime) mutable { - return JSIConverter::toJSI(runtime, result); - }); - } else { - auto result = - std::variant>( - nullptr); - resolve([result = - std::move(result)](jsi::Runtime &runtime) mutable { - return JSIConverter::toJSI(runtime, result); - }); - } - }); - }); -} - -std::unordered_set GPU::getWgslLanguageFeatures() { - wgpu::SupportedWGSLLanguageFeatures supportedFeatures = {}; - _instance.GetWGSLLanguageFeatures(&supportedFeatures); - - std::unordered_set result; - for (size_t i = 0; i < supportedFeatures.featureCount; i++) { - wgpu::WGSLLanguageFeatureName feature = supportedFeatures.features[i]; - std::string name; - switch (feature) { - case wgpu::WGSLLanguageFeatureName::ReadonlyAndReadwriteStorageTextures: - name = "readonly_and_readwrite_storage_textures"; - break; - case wgpu::WGSLLanguageFeatureName::Packed4x8IntegerDotProduct: - name = "packed_4x8_integer_dot_product"; - break; - case wgpu::WGSLLanguageFeatureName::UnrestrictedPointerParameters: - name = "unrestricted_pointer_parameters"; - break; - case wgpu::WGSLLanguageFeatureName::PointerCompositeAccess: - name = "pointer_composite_access"; - break; - case wgpu::WGSLLanguageFeatureName::UniformBufferStandardLayout: - name = "uniform_buffer_standard_layout"; - break; - case wgpu::WGSLLanguageFeatureName::SubgroupId: - name = "subgroup_id"; - break; - case wgpu::WGSLLanguageFeatureName::FragmentDepth: - name = "fragment_depth"; - break; - case wgpu::WGSLLanguageFeatureName::ImmediateAddressSpace: - name = "immediate_address_space"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented: - name = "chromium_testing_unimplemented"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental: - name = "chromium_testing_unsafe_experimental"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental: - name = "chromium_testing_experimental"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch: - name = "chromium_testing_shipped_with_killswitch"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped: - name = "chromium_testing_shipped"; - break; - case wgpu::WGSLLanguageFeatureName::SizedBindingArray: - name = "sized_binding_array"; - break; - case wgpu::WGSLLanguageFeatureName::TexelBuffers: - name = "texel_buffers"; - break; - case wgpu::WGSLLanguageFeatureName::ChromiumPrint: - name = "chromium_print"; - break; - case wgpu::WGSLLanguageFeatureName::TextureAndSamplerLet: - name = "texture_and_sampler_let"; - break; - case wgpu::WGSLLanguageFeatureName::SubgroupUniformity: - name = "subgroup_uniformity"; - break; - case wgpu::WGSLLanguageFeatureName::TextureFormatsTier1: - name = "texture_formats_tier1"; - break; - case wgpu::WGSLLanguageFeatureName::BufferView: - name = "buffer_view"; - break; - case wgpu::WGSLLanguageFeatureName::SwizzleAssignment: - name = "swizzle_assignment"; - break; - case wgpu::WGSLLanguageFeatureName::LinearIndexing: - name = "linear_indexing"; - break; - } - result.insert(name); - } - return result; -} - -wgpu::TextureFormat GPU::getPreferredCanvasFormat() { -#if defined(__ANDROID__) - return wgpu::TextureFormat::RGBA8Unorm; -#else - return wgpu::TextureFormat::BGRA8Unorm; -#endif // defined(__ANDROID__) -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPU.h b/packages/skia/cpp/rnwgpu/api/GPU.h deleted file mode 100644 index 96f0329835..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPU.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUAdapter.h" -#include "descriptors/GPURequestAdapterOptions.h" - -#include - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPU : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPU"; - - explicit GPU(jsi::Runtime &runtime, wgpu::Instance instance); - -public: - std::string getBrand() { return CLASS_NAME; } - - // requestAdapter needs the calling runtime so each runtime gets its own - // RuntimeContext (and ProcessEvents pump on its own thread). - async::AsyncTaskHandle requestAdapter( - jsi::Runtime &runtime, - std::optional> options); - wgpu::TextureFormat getPreferredCanvasFormat(); - - std::unordered_set getWgslLanguageFeatures(); - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPU::getBrand); - installMethodWithRuntime(runtime, prototype, "requestAdapter", - &GPU::requestAdapter); - installMethod(runtime, prototype, "getPreferredCanvasFormat", - &GPU::getPreferredCanvasFormat); - installGetter(runtime, prototype, "wgslLanguageFeatures", - &GPU::getWgslLanguageFeatures); - } - - inline const wgpu::Instance get() { return _instance; } - -private: - wgpu::Instance _instance; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUAdapter.cpp b/packages/skia/cpp/rnwgpu/api/GPUAdapter.cpp deleted file mode 100644 index c975845307..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUAdapter.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include "GPUAdapter.h" - -#include -#include -#include -#include -#include -#include - -#include "Convertors.h" - -#include "GPUFeatures.h" -#include "GPUInternalError.h" -#include "GPUOutOfMemoryError.h" -#include "GPUValidationError.h" -#include "jsi/JSIConverter.h" - -namespace rnwgpu { - -async::AsyncTaskHandle GPUAdapter::requestDevice( - jsi::Runtime &runtime, - std::optional> descriptor) { - wgpu::DeviceDescriptor aDescriptor; - Convertor conv; - if (!conv(aDescriptor, descriptor)) { - throw std::runtime_error("Failed to convert GPUDeviceDescriptor"); - } - auto deviceLostBinding = std::make_shared>(); - // Set device lost callback using new template API - aDescriptor.SetDeviceLostCallback( - wgpu::CallbackMode::AllowSpontaneous, - [deviceLostBinding](const wgpu::Device & /*device*/, - wgpu::DeviceLostReason reason, - wgpu::StringView message) { - const char *lostReason = ""; - switch (reason) { - case wgpu::DeviceLostReason::Destroyed: - lostReason = "Destroyed"; - break; - case wgpu::DeviceLostReason::Unknown: - lostReason = "Unknown"; - break; - default: - lostReason = "Unknown"; - } - std::string msg = - message.length ? std::string(message.data, message.length) : ""; - fprintf(stderr, "GPU Device Lost (%s): %s\n", lostReason, msg.c_str()); - if (auto deviceHost = deviceLostBinding->lock()) { - deviceHost->notifyDeviceLost(reason, std::move(msg)); - } - }); - - // Set uncaptured error callback using new template API - aDescriptor.SetUncapturedErrorCallback([](const wgpu::Device &device, - wgpu::ErrorType type, - wgpu::StringView message) { - const char *errorType = ""; - switch (type) { - case wgpu::ErrorType::Validation: - errorType = "Validation"; - break; - case wgpu::ErrorType::OutOfMemory: - errorType = "Out of Memory"; - break; - case wgpu::ErrorType::Internal: - errorType = "Internal"; - break; - case wgpu::ErrorType::Unknown: - errorType = "Unknown"; - break; - default: - errorType = "Unknown"; - } - std::string fullMessage = - message.length > 0 ? std::string(errorType) + ": " + - std::string(message.data, message.length) - : "no message"; - fprintf(stderr, "%s", fullMessage.c_str()); - - // Look up the GPUDevice from the registry and notify it - auto *gpuDevice = GPUDeviceRegistry::getInstance().getDevice(device.Get()); - if (gpuDevice != nullptr) { - std::string messageStr = - message.length > 0 ? std::string(message.data, message.length) : ""; - - GPUErrorVariant error; - switch (type) { - case wgpu::ErrorType::Validation: - error = std::make_shared(messageStr); - break; - case wgpu::ErrorType::OutOfMemory: - error = std::make_shared(messageStr); - break; - case wgpu::ErrorType::Internal: - case wgpu::ErrorType::Unknown: - default: - error = std::make_shared(messageStr); - break; - } - gpuDevice->notifyUncapturedError(std::move(error)); - } - }); - std::string label = - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""; - - auto creationRuntime = getCreationRuntime(); - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). The GPUDevice is also - // bound to this context, honoring the contract that a device belongs to the - // runtime that requested it. - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask( - [this, aDescriptor, descriptor, label = std::move(label), - deviceLostBinding, context, - creationRuntime](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { - // Build a local mutable copy so we can chain Dawn's device toggles. - // The toggle name strings are owned by `descriptor` (captured above), - // and the const char* / DawnTogglesDescriptor locals live for the - // whole synchronous RequestDevice call below, which is when Dawn reads - // the chained struct. - wgpu::DeviceDescriptor deviceDesc = aDescriptor; - wgpu::DawnTogglesDescriptor toggles{}; - std::vector enabledToggles; - std::vector disabledToggles; - if (descriptor.has_value() && descriptor.value()->dawnToggles) { - const auto &dawnToggles = descriptor.value()->dawnToggles.value(); - if (dawnToggles->enabledToggles) { - for (const auto &t : dawnToggles->enabledToggles.value()) { - enabledToggles.push_back(t.c_str()); - } - toggles.enabledToggleCount = enabledToggles.size(); - toggles.enabledToggles = enabledToggles.data(); - } - if (dawnToggles->disabledToggles) { - for (const auto &t : dawnToggles->disabledToggles.value()) { - disabledToggles.push_back(t.c_str()); - } - toggles.disabledToggleCount = disabledToggles.size(); - toggles.disabledToggles = disabledToggles.data(); - } - deviceDesc.nextInChain = &toggles; - } - _instance.RequestDevice( - &deviceDesc, wgpu::CallbackMode::AllowProcessEvents, - [context, resolve, reject, label, creationRuntime, - deviceLostBinding](wgpu::RequestDeviceStatus status, - wgpu::Device device, wgpu::StringView message) { - if (message.length) { - fprintf(stderr, "%s", message.data); - } - - if (status != wgpu::RequestDeviceStatus::Success || !device) { - std::string error = - message.length ? std::string(message.data, message.length) - : "Failed to request device"; - reject(std::move(error)); - return; - } - - // SetLoggingCallback is a repeatable callback (no callback mode), - // which rejects capturing lambdas. Pass the runtime pointer - // through Dawn's userdata argument instead of capturing it. - device.SetLoggingCallback( - [](wgpu::LoggingType type, wgpu::StringView msg, - jsi::Runtime *runtime) { - if (runtime == nullptr) { - return; - } - const char *logLevel = ""; - switch (type) { - case wgpu::LoggingType::Warning: - logLevel = "Warning"; - fprintf(stderr, "WebGPU Warning: %.*s\n", - static_cast(msg.length), msg.data); - break; - case wgpu::LoggingType::Error: - logLevel = "Error"; - fprintf(stderr, "WebGPU Error: %.*s\n", - static_cast(msg.length), msg.data); - break; - case wgpu::LoggingType::Verbose: - logLevel = "Verbose"; - break; - case wgpu::LoggingType::Info: - logLevel = "Info"; - break; - default: - logLevel = "Unknown"; - fprintf(stderr, "%s: %.*s\n", logLevel, - static_cast(msg.length), msg.data); - } - }, - creationRuntime); - - auto deviceHost = std::make_shared(std::move(device), - context, label); - *deviceLostBinding = deviceHost; - resolve([deviceHost = std::move(deviceHost)]( - jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, deviceHost); - }); - }); - }); -} - -std::unordered_set GPUAdapter::getFeatures() { - wgpu::SupportedFeatures supportedFeatures; - _instance.GetFeatures(&supportedFeatures); - std::unordered_set result; - for (size_t i = 0; i < supportedFeatures.featureCount; ++i) { - auto feature = supportedFeatures.features[i]; - std::string name; - convertEnumToJSUnion(feature, &name); - if (name != "") { - result.insert(name); - } - } - return result; -} - -std::shared_ptr GPUAdapter::getLimits() { - wgpu::Limits limits{}; - if (!_instance.GetLimits(&limits)) { - throw std::runtime_error("Failed to get limits"); - } - return std::make_shared(limits); -} - -std::shared_ptr GPUAdapter::getInfo() { - wgpu::AdapterInfo info = {}; - _instance.GetInfo(&info); - return std::make_shared(info); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUAdapter.h b/packages/skia/cpp/rnwgpu/api/GPUAdapter.h deleted file mode 100644 index 1294ca0d9c..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUAdapter.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUAdapterInfo.h" -#include "GPUDevice.h" -#include "GPUSupportedLimits.h" -#include "descriptors/GPUDeviceDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUAdapter : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUAdapter"; - - explicit GPUAdapter(wgpu::Adapter instance, - std::shared_ptr async) - : NativeObject(CLASS_NAME), _instance(instance), _async(async) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - async::AsyncTaskHandle - requestDevice(jsi::Runtime &runtime, - std::optional> descriptor); - - std::unordered_set getFeatures(); - std::shared_ptr getLimits(); - std::shared_ptr getInfo(); - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUAdapter::getBrand); - installMethodWithRuntime(runtime, prototype, "requestDevice", - &GPUAdapter::requestDevice); - installGetter(runtime, prototype, "features", &GPUAdapter::getFeatures); - installGetter(runtime, prototype, "limits", &GPUAdapter::getLimits); - installGetter(runtime, prototype, "info", &GPUAdapter::getInfo); - } - - inline const wgpu::Adapter get() { return _instance; } - -private: - wgpu::Adapter _instance; - std::shared_ptr _async; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUAdapterInfo.h b/packages/skia/cpp/rnwgpu/api/GPUAdapterInfo.h deleted file mode 100644 index e6ca5975e9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUAdapterInfo.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "Convertors.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUAdapterInfo : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUAdapterInfo"; - - explicit GPUAdapterInfo(wgpu::AdapterInfo &info) - : NativeObject(CLASS_NAME), _vendor(info.vendor), - _architecture(info.architecture), _device(info.device), - _description(info.description), - _isFallbackAdapter(info.adapterType == wgpu::AdapterType::CPU) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getVendor() { return _vendor; } - std::string getArchitecture() { return _architecture; } - std::string getDevice() { return _device; } - std::string getDescription() { return _description; } - bool getIsFallbackAdapter() { return _isFallbackAdapter; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUAdapterInfo::getBrand); - installGetter(runtime, prototype, "vendor", &GPUAdapterInfo::getVendor); - installGetter(runtime, prototype, "architecture", - &GPUAdapterInfo::getArchitecture); - installGetter(runtime, prototype, "device", &GPUAdapterInfo::getDevice); - installGetter(runtime, prototype, "description", - &GPUAdapterInfo::getDescription); - installGetter(runtime, prototype, "isFallbackAdapter", - &GPUAdapterInfo::getIsFallbackAdapter); - } - -private: - std::string _vendor; - std::string _architecture; - std::string _device; - std::string _description; - bool _isFallbackAdapter; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUBindGroup.cpp b/packages/skia/cpp/rnwgpu/api/GPUBindGroup.cpp deleted file mode 100644 index 07826a15c0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUBindGroup.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "GPUBindGroup.h" - -namespace rnwgpu {} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPUBindGroup.h b/packages/skia/cpp/rnwgpu/api/GPUBindGroup.h deleted file mode 100644 index 4cfad22802..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUBindGroup.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUBindGroup : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUBindGroup"; - - explicit GPUBindGroup(wgpu::BindGroup instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUBindGroup::getBrand); - installGetterSetter(runtime, prototype, "label", &GPUBindGroup::getLabel, - &GPUBindGroup::setLabel); - } - - 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; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUBindGroupLayout.h b/packages/skia/cpp/rnwgpu/api/GPUBindGroupLayout.h deleted file mode 100644 index a4322b3a22..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUBindGroupLayout.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUBindGroupLayout : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUBindGroupLayout"; - - explicit GPUBindGroupLayout(wgpu::BindGroupLayout instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUBindGroupLayout::getBrand); - installGetterSetter(runtime, prototype, "label", - &GPUBindGroupLayout::getLabel, - &GPUBindGroupLayout::setLabel); - } - - 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; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUBuffer.cpp b/packages/skia/cpp/rnwgpu/api/GPUBuffer.cpp deleted file mode 100644 index 54b8aa1021..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUBuffer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "GPUBuffer.h" - -#include -#include - -#include "Convertors.h" - -namespace rnwgpu { - -std::shared_ptr -GPUBuffer::getMappedRange(std::optional o, std::optional size) { - auto offset = o.value_or(0); - uint64_t s = size.has_value() ? size.value() : (_instance.GetSize() - offset); - - // uint64_t start = offset; - // uint64_t end = offset + s; - // for (auto& mapping : mappings_) { - // if (mapping.Intersects(start, end)) { - // Errors::OperationError(env).ThrowAsJavaScriptException(); - // return {}; - // } - // } - - auto *ptr = - (_instance.GetUsage() & wgpu::BufferUsage::MapWrite) - ? _instance.GetMappedRange(offset, s) - : const_cast(_instance.GetConstMappedRange(offset, s)); - if (!ptr) { - throw std::runtime_error("Failed to get getMappedRange"); - } - auto array_buffer = std::make_shared(ptr, s, 1); - // TODO(crbug.com/dawn/1135): Ownership here is the wrong way around. - // mappings_.emplace_back(Mapping{start, end, - // Napi::Persistent(array_buffer)}); - return array_buffer; -} - -void GPUBuffer::destroy() { _instance.Destroy(); } - -async::AsyncTaskHandle GPUBuffer::mapAsync(jsi::Runtime &runtime, - uint64_t modeIn, - std::optional offset, - std::optional size) { - Convertor conv; - wgpu::MapMode mode; - if (!conv(mode, modeIn)) { - throw std::runtime_error("Couldn't get MapMode"); - } - uint64_t rangeSize = size.has_value() - ? size.value() - : (_instance.GetSize() - offset.value_or(0)); - auto bufferHandle = _instance; - uint64_t resolvedOffset = offset.value_or(0); - - // Post to the CALLING runtime's context, not the one captured at buffer - // creation (_async): the buffer may have been created on another runtime and - // boxed across (e.g. device created on the main JS runtime, mapAsync called - // from a worklet). The returned Promise lives on the calling runtime, so it - // must be settled from that runtime's own thread — and postTask itself - // schedules the pump through its context's runtime (setTimeout), which is - // only safe for the runtime we are currently executing on. - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask( - [bufferHandle, mode, resolvedOffset, - rangeSize](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { - bufferHandle.MapAsync(mode, resolvedOffset, rangeSize, - wgpu::CallbackMode::AllowProcessEvents, - [resolve, reject](wgpu::MapAsyncStatus status, - wgpu::StringView message) { - switch (status) { - case wgpu::MapAsyncStatus::Success: - resolve(nullptr); - break; - case wgpu::MapAsyncStatus::CallbackCancelled: - reject("MapAsyncStatus::CallbackCancelled"); - break; - case wgpu::MapAsyncStatus::Error: - reject("MapAsyncStatus::Error"); - break; - case wgpu::MapAsyncStatus::Aborted: - reject("MapAsyncStatus::Aborted"); - break; - default: - reject( - "MapAsyncStatus: " + - std::to_string(static_cast(status))); - break; - } - }); - }); -} - -void GPUBuffer::unmap() { _instance.Unmap(); } - -uint64_t GPUBuffer::getSize() { return _instance.GetSize(); } - -double GPUBuffer::getUsage() { - return static_cast(_instance.GetUsage()); -} - -wgpu::BufferMapState GPUBuffer::getMapState() { - return _instance.GetMapState(); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUBuffer.h b/packages/skia/cpp/rnwgpu/api/GPUBuffer.h deleted file mode 100644 index 00ae857662..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUBuffer.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "rnwgpu/ArrayBuffer.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUBuffer : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUBuffer"; - - explicit GPUBuffer(wgpu::Buffer instance, - std::shared_ptr async, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _async(async), - _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - async::AsyncTaskHandle mapAsync(jsi::Runtime &runtime, uint64_t modeIn, - std::optional offset, - std::optional size); - std::shared_ptr getMappedRange(std::optional offset, - std::optional size); - void unmap(); - void destroy(); - - uint64_t getSize(); - double getUsage(); - wgpu::BufferMapState getMapState(); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUBuffer::getBrand); - installMethodWithRuntime(runtime, prototype, "mapAsync", - &GPUBuffer::mapAsync); - installMethod(runtime, prototype, "getMappedRange", - &GPUBuffer::getMappedRange); - installMethod(runtime, prototype, "unmap", &GPUBuffer::unmap); - installMethod(runtime, prototype, "destroy", &GPUBuffer::destroy); - installGetter(runtime, prototype, "size", &GPUBuffer::getSize); - installGetter(runtime, prototype, "usage", &GPUBuffer::getUsage); - installGetter(runtime, prototype, "mapState", &GPUBuffer::getMapState); - installGetterSetter(runtime, prototype, "label", &GPUBuffer::getLabel, - &GPUBuffer::setLabel); - } - - inline const wgpu::Buffer get() { return _instance; } - - size_t getMemoryPressure() override { return static_cast(getSize()); } - -private: - wgpu::Buffer _instance; - std::shared_ptr _async; - std::string _label; - struct Mapping { - uint64_t start; - uint64_t end; - inline bool Intersects(uint64_t s, uint64_t e) const { - return s < end && e > start; - } - std::shared_ptr buffer; - }; - std::vector mappings; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.cpp b/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.cpp deleted file mode 100644 index b14dce1297..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "GPUCanvasContext.h" -#include "Convertors.h" -#include -#include -#include -#include - -namespace rnwgpu { - -void GPUCanvasContext::configure( - std::shared_ptr configuration) { - Convertor conv; - wgpu::SurfaceConfiguration surfaceConfiguration; - surfaceConfiguration.device = configuration->device->get(); - if (!conv(surfaceConfiguration.usage, configuration->usage) || - !conv(surfaceConfiguration.format, configuration->format)) { - throw std::runtime_error("Error with SurfaceConfiguration"); - } - // viewFormats are deep-copied into SurfaceInfo (which outlives this call); - // Convertor-allocated arrays would dangle. - std::vector viewFormats; - if (configuration->viewFormats.has_value()) { - viewFormats = configuration->viewFormats.value(); - } - -#ifdef __APPLE__ - surfaceConfiguration.alphaMode = configuration->alphaMode; -#endif - surfaceConfiguration.presentMode = wgpu::PresentMode::Fifo; - _surfaceInfo->configure(surfaceConfiguration, std::move(viewFormats)); -} - -void GPUCanvasContext::unconfigure() { _surfaceInfo->unconfigure(); } - -std::shared_ptr GPUCanvasContext::getCurrentTexture() { - if (!_surfaceInfo->isConfigured()) { - // Web parity: on the web this is an InvalidStateError, not a crash. - throw std::runtime_error( - "[WebGPU] getCurrentTexture() called on a canvas context that is not " - "configured; call context.configure() first"); - } - // The drawing buffer tracks canvas.width/height (like on the web); resize it - // lazily when they changed. Sizes are clamped to 1 so a canvas that has not - // been laid out yet (0x0) keeps working. - auto prevSize = _surfaceInfo->getConfig(); - auto width = std::max(1, _canvas->getWidth()); - auto height = std::max(1, _canvas->getHeight()); - auto sizeHasChanged = prevSize.width != static_cast(width) || - prevSize.height != static_cast(height); - if (sizeHasChanged) { - _surfaceInfo->reconfigure(width, height); - } - - auto texture = _surfaceInfo->getCurrentTexture(); - if (texture == nullptr) { - throw std::runtime_error( - "[WebGPU] getCurrentTexture() failed to acquire a texture"); - } - - auto size = _surfaceInfo->getSize(); - _canvas->setClientWidth(size.width); - _canvas->setClientHeight(size.height); - - return std::make_shared(texture, "", false); -} - -void GPUCanvasContext::present() { - // presentFrame() is the end-of-frame boundary: it presents when this frame's - // texture was acquired from the on-screen surface (offscreen and dropped - // frames are skipped), clears the frame state, and adopts any surface that - // attached while the frame was in flight. - _surfaceInfo->presentFrame(); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.h b/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.h deleted file mode 100644 index 9691dabccb..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCanvasContext.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/NativeObject.h" - -#include "GPU.h" -#include "GPUTexture.h" -#include "descriptors/GPUCanvasConfiguration.h" -#include "rnwgpu/Canvas.h" -#include "rnwgpu/SurfaceRegistry.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUCanvasContext : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUCanvasContext"; - - GPUCanvasContext(std::shared_ptr gpu, int contextId, int width, - int height) - : NativeObject(CLASS_NAME), _gpu(std::move(gpu)) { - _canvas = std::make_shared(nullptr, width, height); - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - _surfaceInfo = - registry.getSurfaceInfoOrCreate(contextId, _gpu->get(), width, height); - } - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr getCanvas() { return _canvas; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUCanvasContext::getBrand); - installGetter(runtime, prototype, "canvas", &GPUCanvasContext::getCanvas); - installMethod(runtime, prototype, "configure", - &GPUCanvasContext::configure); - installMethod(runtime, prototype, "unconfigure", - &GPUCanvasContext::unconfigure); - installMethod(runtime, prototype, "getCurrentTexture", - &GPUCanvasContext::getCurrentTexture); - installMethod(runtime, prototype, "present", &GPUCanvasContext::present); - } - - inline const wgpu::Surface get() { return nullptr; } - void configure(std::shared_ptr configuration); - void unconfigure(); - std::shared_ptr getCurrentTexture(); - // Present is explicit on every runtime (main JS, Reanimated UI, and dedicated - // worklet runtimes). It runs synchronously on the calling thread, preserving - // Dawn surface thread-affinity; frames rendered offscreen (no surface - // attached) are skipped. It is also the end-of-frame boundary at which a - // newly attached native surface is adopted (see SurfaceInfo). - void present(); - -private: - std::shared_ptr _canvas; - std::shared_ptr _surfaceInfo; - std::shared_ptr _gpu; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCommandBuffer.h b/packages/skia/cpp/rnwgpu/api/GPUCommandBuffer.h deleted file mode 100644 index 6e77f17696..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCommandBuffer.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUCommandBuffer : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUCommandBuffer"; - - explicit GPUCommandBuffer(wgpu::CommandBuffer instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUCommandBuffer::getBrand); - installGetterSetter(runtime, prototype, "label", - &GPUCommandBuffer::getLabel, - &GPUCommandBuffer::setLabel); - } - - inline const wgpu::CommandBuffer get() { return _instance; } - -private: - wgpu::CommandBuffer _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.cpp b/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.cpp deleted file mode 100644 index 7ef1ce0645..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "GPUCommandEncoder.h" - -#include -#include -#include - -#include "Convertors.h" - -namespace rnwgpu { - -void GPUCommandEncoder::copyBufferToBuffer( - std::shared_ptr source, uint64_t sourceOffset, - std::shared_ptr destination, uint64_t destinationOffset, - uint64_t size) { - Convertor conv; - - wgpu::Buffer src{}; - wgpu::Buffer dst{}; - if (!conv(src, source) || // - !conv(dst, destination)) { - return; - } - _instance.CopyBufferToBuffer(src, sourceOffset, dst, destinationOffset, size); -} - -std::shared_ptr GPUCommandEncoder::finish( - std::optional> descriptor) { - wgpu::CommandBufferDescriptor desc{}; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error( - "GPUCommandEncoder::finish(): error with GPUCommandBufferDescriptor"); - } - auto commandBuffer = _instance.Finish(&desc); - return std::make_shared( - commandBuffer, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -std::shared_ptr GPUCommandEncoder::beginRenderPass( - std::shared_ptr descriptor) { - - wgpu::RenderPassDescriptor desc{}; - wgpu::RenderPassMaxDrawCount maxDrawCountDesc{}; - desc.nextInChain = &maxDrawCountDesc; - Convertor conv; - - // TODO: why is this not in Converter - if (!conv(desc.colorAttachments, desc.colorAttachmentCount, - descriptor->colorAttachments) || - !conv(desc.depthStencilAttachment, descriptor->depthStencilAttachment) || - !conv(desc.label, descriptor->label) || - !conv(desc.occlusionQuerySet, descriptor->occlusionQuerySet) || - !conv(desc.timestampWrites, descriptor->timestampWrites) || - !conv(maxDrawCountDesc.maxDrawCount, descriptor->maxDrawCount)) { - throw std::runtime_error("PUCommandEncoder::beginRenderPass(): couldn't " - "get GPURenderPassDescriptor"); - } - auto renderPass = _instance.BeginRenderPass(&desc); - return std::make_shared(renderPass, - descriptor->label.value_or("")); -} - -void GPUCommandEncoder::copyTextureToBuffer( - std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize) { - Convertor conv; - wgpu::TexelCopyTextureInfo src{}; - wgpu::TexelCopyBufferInfo dst{}; - wgpu::Extent3D size{}; - if (!conv(src, source) || // - !conv(dst, destination) || // - !conv(size, copySize)) { - return; - } - _instance.CopyTextureToBuffer(&src, &dst, &size); -} - -void GPUCommandEncoder::copyTextureToTexture( - std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize) { - Convertor conv; - - wgpu::TexelCopyTextureInfo src{}; - wgpu::TexelCopyTextureInfo dst{}; - wgpu::Extent3D size{}; - if (!conv(src, source) || // - !conv(dst, destination) || // - !conv(size, copySize)) { - return; - } - - _instance.CopyTextureToTexture(&src, &dst, &size); -} - -std::shared_ptr GPUCommandEncoder::beginComputePass( - std::optional> descriptor) { - wgpu::ComputePassDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUCommandEncoder.beginComputePass(): couldn't " - "access GPUComputePassDescriptor."); - } - auto computePass = _instance.BeginComputePass(&desc); - return std::make_shared( - computePass, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -void GPUCommandEncoder::resolveQuerySet(std::shared_ptr querySet, - uint32_t firstQuery, - uint32_t queryCount, - std::shared_ptr destination, - uint64_t destinationOffset) { - Convertor conv; - - wgpu::QuerySet q{}; - uint32_t f = 0; - uint32_t c = 0; - wgpu::Buffer b{}; - uint64_t o = 0; - - if (!conv(q, querySet) || // - !conv(f, firstQuery) || // - !conv(c, queryCount) || // - !conv(b, destination) || // - !conv(o, destinationOffset)) { - return; - } - - _instance.ResolveQuerySet(q, f, c, b, o); -} - -void GPUCommandEncoder::copyBufferToTexture( - std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize) { - Convertor conv; - - wgpu::TexelCopyBufferInfo src{}; - wgpu::TexelCopyTextureInfo dst{}; - wgpu::Extent3D size{}; - if (!conv(src, source) || // - !conv(dst, destination) || // - !conv(size, copySize)) { - return; - } - - _instance.CopyBufferToTexture(&src, &dst, &size); -} - -void GPUCommandEncoder::clearBuffer(std::shared_ptr buffer, - std::optional offset, - std::optional size) { - Convertor conv; - - wgpu::Buffer b{}; - uint64_t s = wgpu::kWholeSize; - if (!conv(b, buffer) || // - !conv(s, size)) { - return; - } - - _instance.ClearBuffer(b, offset.value_or(0), s); -} - -void GPUCommandEncoder::pushDebugGroup(std::string groupLabel) { - _instance.PushDebugGroup(groupLabel.c_str()); -} - -void GPUCommandEncoder::popDebugGroup() { _instance.PopDebugGroup(); } - -void GPUCommandEncoder::insertDebugMarker(std::string markerLabel) { - _instance.InsertDebugMarker(markerLabel.c_str()); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.h b/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.h deleted file mode 100644 index c5a216d532..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCommandEncoder.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBuffer.h" -#include "GPUCommandBuffer.h" -#include "GPUComputePassEncoder.h" -#include "GPUExtent3D.h" -#include "GPUQuerySet.h" -#include "GPURenderPassEncoder.h" -#include "descriptors/GPUCommandBufferDescriptor.h" -#include "descriptors/GPUComputePassDescriptor.h" -#include "descriptors/GPUImageCopyBuffer.h" -#include "descriptors/GPUImageCopyTexture.h" -#include "descriptors/GPURenderPassDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUCommandEncoder : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUCommandEncoder"; - - explicit GPUCommandEncoder(wgpu::CommandEncoder instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr - beginRenderPass(std::shared_ptr descriptor); - std::shared_ptr beginComputePass( - std::optional> descriptor); - void copyBufferToBuffer(std::shared_ptr source, - uint64_t sourceOffset, - std::shared_ptr destination, - uint64_t destinationOffset, uint64_t size); - void copyBufferToTexture(std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize); - void copyTextureToBuffer(std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize); - void copyTextureToTexture(std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize); - void clearBuffer(std::shared_ptr buffer, - std::optional offset, - std::optional size); - void resolveQuerySet(std::shared_ptr querySet, - uint32_t firstQuery, uint32_t queryCount, - std::shared_ptr destination, - uint64_t destinationOffset); - std::shared_ptr - finish(std::optional> descriptor); - void pushDebugGroup(std::string groupLabel); - void popDebugGroup(); - void insertDebugMarker(std::string markerLabel); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUCommandEncoder::getBrand); - installMethod(runtime, prototype, "beginRenderPass", - &GPUCommandEncoder::beginRenderPass); - installMethod(runtime, prototype, "beginComputePass", - &GPUCommandEncoder::beginComputePass); - installMethod(runtime, prototype, "copyBufferToBuffer", - &GPUCommandEncoder::copyBufferToBuffer); - installMethod(runtime, prototype, "copyBufferToTexture", - &GPUCommandEncoder::copyBufferToTexture); - installMethod(runtime, prototype, "copyTextureToBuffer", - &GPUCommandEncoder::copyTextureToBuffer); - installMethod(runtime, prototype, "copyTextureToTexture", - &GPUCommandEncoder::copyTextureToTexture); - installMethod(runtime, prototype, "clearBuffer", - &GPUCommandEncoder::clearBuffer); - installMethod(runtime, prototype, "resolveQuerySet", - &GPUCommandEncoder::resolveQuerySet); - installMethod(runtime, prototype, "finish", &GPUCommandEncoder::finish); - installMethod(runtime, prototype, "pushDebugGroup", - &GPUCommandEncoder::pushDebugGroup); - installMethod(runtime, prototype, "popDebugGroup", - &GPUCommandEncoder::popDebugGroup); - installMethod(runtime, prototype, "insertDebugMarker", - &GPUCommandEncoder::insertDebugMarker); - installGetterSetter(runtime, prototype, "label", - &GPUCommandEncoder::getLabel, - &GPUCommandEncoder::setLabel); - } - - inline const wgpu::CommandEncoder get() { return _instance; } - -private: - wgpu::CommandEncoder _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCompilationInfo.h b/packages/skia/cpp/rnwgpu/api/GPUCompilationInfo.h deleted file mode 100644 index acde2378cb..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCompilationInfo.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -struct GPUCompilationMessageData { - std::string message; - wgpu::CompilationMessageType type; - uint64_t lineNum; - uint64_t linePos; - uint64_t offset; - uint64_t length; -}; - -class GPUCompilationInfo : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUCompilationInfo"; - - GPUCompilationInfo() : NativeObject(CLASS_NAME) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::vector getMessages() { return _messages; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUCompilationInfo::getBrand); - installGetter(runtime, prototype, "messages", - &GPUCompilationInfo::getMessages); - } - -private: - std::vector _messages; - friend class GPUShaderModule; -}; - -template <> struct JSIConverter> { - static std::vector - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - throw std::runtime_error("Invalid GPUCompilationMessageData::fromJSI()"); - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::vector arg) { - jsi::Array result = jsi::Array(runtime, arg.size()); - for (size_t i = 0; i < arg.size(); i++) { - const auto &message = arg[i]; - jsi::Object messageObj(runtime); - messageObj.setProperty( - runtime, "message", - jsi::String::createFromUtf8(runtime, message.message)); - std::string typeStr; - EnumMapper::convertEnumToJSUnion(message.type, &typeStr); - messageObj.setProperty(runtime, "type", - jsi::String::createFromUtf8(runtime, typeStr)); - messageObj.setProperty(runtime, "lineNum", - static_cast(message.lineNum)); - messageObj.setProperty(runtime, "linePos", - static_cast(message.linePos)); - messageObj.setProperty(runtime, "offset", - static_cast(message.offset)); - messageObj.setProperty(runtime, "length", - static_cast(message.length)); - result.setValueAtIndex(runtime, i, messageObj); - } - return result; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUCompilationMessage.h b/packages/skia/cpp/rnwgpu/api/GPUCompilationMessage.h deleted file mode 100644 index d8d43f2144..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUCompilationMessage.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUCompilationMessage : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUCompilationMessage"; - - explicit GPUCompilationMessage(wgpu::CompilationMessage instance) - : NativeObject(CLASS_NAME), _instance(instance) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPUCompilationMessage::getBrand); - } - - inline const wgpu::CompilationMessage get() { return _instance; } - -private: - wgpu::CompilationMessage _instance; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.cpp b/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.cpp deleted file mode 100644 index b74f273a01..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "GPUComputePassEncoder.h" -#include -#include - -namespace rnwgpu { - -void GPUComputePassEncoder::setPipeline( - std::shared_ptr pipeline) { - _instance.SetPipeline(pipeline->get()); -} - -void GPUComputePassEncoder::end() { _instance.End(); } - -void GPUComputePassEncoder::setBindGroup( - uint32_t index, - std::variant> bindGroup, - std::optional> dynamicOffsets) { - auto dynOffsets = dynamicOffsets.value_or(std::vector()); - if (dynOffsets.size() == 0) { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(index, nullptr, 0, nullptr); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(index, group->get(), 0, nullptr); - } - } else { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(index, nullptr, dynOffsets.size(), - dynamicOffsets->data()); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(index, group->get(), dynOffsets.size(), - dynamicOffsets->data()); - } - } -} - -void GPUComputePassEncoder::dispatchWorkgroups( - uint32_t workgroupCountX, std::optional workgroupCountY, - std::optional workgroupCountZ) { - _instance.DispatchWorkgroups(workgroupCountX, workgroupCountY.value_or(1), - workgroupCountZ.value_or(1)); -} - -void GPUComputePassEncoder::dispatchWorkgroupsIndirect( - std::shared_ptr indirectBuffer, uint64_t indirectOffset) { - _instance.DispatchWorkgroupsIndirect(indirectBuffer->get(), indirectOffset); -} - -void GPUComputePassEncoder::pushDebugGroup(std::string groupLabel) { - _instance.PushDebugGroup(groupLabel.c_str()); -} - -void GPUComputePassEncoder::popDebugGroup() { _instance.PopDebugGroup(); } - -void GPUComputePassEncoder::insertDebugMarker(std::string markerLabel) { - _instance.InsertDebugMarker(markerLabel.c_str()); -} - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.h b/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.h deleted file mode 100644 index 1c5ddf1d81..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUComputePassEncoder.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBindGroup.h" -#include "GPUBuffer.h" -#include "GPUComputePipeline.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUComputePassEncoder : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUComputePassEncoder"; - - explicit GPUComputePassEncoder(wgpu::ComputePassEncoder instance, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - void setPipeline(std::shared_ptr pipeline); - void dispatchWorkgroups(uint32_t workgroupCountX, - std::optional workgroupCountY, - std::optional workgroupCountZ); - void dispatchWorkgroupsIndirect(std::shared_ptr indirectBuffer, - uint64_t indirectOffset); - void end(); - void pushDebugGroup(std::string groupLabel); - void popDebugGroup(); - void insertDebugMarker(std::string markerLabel); - void setBindGroup( - uint32_t index, - std::variant> bindGroup, - std::optional> dynamicOffsets); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPUComputePassEncoder::getBrand); - installMethod(runtime, prototype, "setPipeline", - &GPUComputePassEncoder::setPipeline); - installMethod(runtime, prototype, "dispatchWorkgroups", - &GPUComputePassEncoder::dispatchWorkgroups); - installMethod(runtime, prototype, "dispatchWorkgroupsIndirect", - &GPUComputePassEncoder::dispatchWorkgroupsIndirect); - installMethod(runtime, prototype, "end", &GPUComputePassEncoder::end); - installMethod(runtime, prototype, "pushDebugGroup", - &GPUComputePassEncoder::pushDebugGroup); - installMethod(runtime, prototype, "popDebugGroup", - &GPUComputePassEncoder::popDebugGroup); - installMethod(runtime, prototype, "insertDebugMarker", - &GPUComputePassEncoder::insertDebugMarker); - installMethod(runtime, prototype, "setBindGroup", - &GPUComputePassEncoder::setBindGroup); - installGetterSetter(runtime, prototype, "label", - &GPUComputePassEncoder::getLabel, - &GPUComputePassEncoder::setLabel); - } - - inline const wgpu::ComputePassEncoder get() { return _instance; } - -private: - wgpu::ComputePassEncoder _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.cpp b/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.cpp deleted file mode 100644 index 4a8be1d726..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "GPUComputePipeline.h" -#include - -namespace rnwgpu { - -std::shared_ptr -GPUComputePipeline::getBindGroupLayout(uint32_t groupIndex) { - auto bindGroup = _instance.GetBindGroupLayout(groupIndex); - return std::make_shared(bindGroup, ""); -} - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.h b/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.h deleted file mode 100644 index c360a0d695..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUComputePipeline.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBindGroupLayout.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUComputePipeline : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUComputePipeline"; - - explicit GPUComputePipeline(wgpu::ComputePipeline instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr getBindGroupLayout(uint32_t index); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUComputePipeline::getBrand); - installMethod(runtime, prototype, "getBindGroupLayout", - &GPUComputePipeline::getBindGroupLayout); - installGetterSetter(runtime, prototype, "label", - &GPUComputePipeline::getLabel, - &GPUComputePipeline::setLabel); - } - - 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; - friend class GPUDevice; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUDevice.cpp b/packages/skia/cpp/rnwgpu/api/GPUDevice.cpp deleted file mode 100644 index 3d9a51c870..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUDevice.cpp +++ /dev/null @@ -1,613 +0,0 @@ -#include "GPUDevice.h" - -#include -#include -#include -#include -#include - -#include - -#include "Convertors.h" -#include "NativeBufferUtils.h" -#include "jsi/JSIConverter.h" - -#include "GPUFeatures.h" -#include "GPUInternalError.h" -#include "GPUOutOfMemoryError.h" -#include "GPUValidationError.h" - -namespace rnwgpu { - -void GPUDevice::notifyDeviceLost(wgpu::DeviceLostReason reason, - std::string message) { - std::optional resolveToCall; - std::shared_ptr info; - { - std::lock_guard lock(_lostMutex); - if (_lostSettled) { - return; - } - - _lostSettled = true; - _lostInfo = std::make_shared(reason, std::move(message)); - info = _lostInfo; - - if (_lostResolve.has_value()) { - resolveToCall = std::move(*_lostResolve); - _lostResolve.reset(); - } - - _lostHandle.reset(); - } - - // Settle outside the lock: resolve() only enqueues onto the JS thread. - if (resolveToCall.has_value()) { - (*resolveToCall)([info](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI(runtime, - info); - }); - } -} - -void GPUDevice::forceLossForTesting() { - // wgpu::StringView view("forceLossForTesting invoked from JS"); - _instance.ForceLoss(wgpu::DeviceLostReason::Unknown, - "forceLossForTesting invoked from JS"); -} - -std::shared_ptr -GPUDevice::createBuffer(std::shared_ptr descriptor) { - wgpu::BufferDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error( - "GPUDevice::createBuffer(): Error with GPUBufferDescriptor"); - } - auto result = _instance.CreateBuffer(&desc); - return std::make_shared(result, _async, - descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::getLimits() { - wgpu::Limits limits{}; - if (!_instance.GetLimits(&limits)) { - throw std::runtime_error("failed to get device limits"); - } - return std::make_shared(limits); -} - -std::shared_ptr GPUDevice::getQueue() { - auto result = _instance.GetQueue(); - return std::make_shared(result, _async, _label); -} - -std::shared_ptr GPUDevice::createCommandEncoder( - std::optional> descriptor) { - wgpu::CommandEncoderDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("Error with GPUCommandEncoderDescriptor"); - } - auto result = _instance.CreateCommandEncoder(&desc); - return std::make_shared( - result, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -void GPUDevice::destroy() { - _instance.Destroy(); - notifyDeviceLost(wgpu::DeviceLostReason::Destroyed, "device was destroyed"); -} - -std::shared_ptr -GPUDevice::createTexture(std::shared_ptr descriptor) { - wgpu::TextureDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("Error with GPUTextureDescriptor"); - } - auto texture = _instance.CreateTexture(&desc); - return std::make_shared(texture, descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createShaderModule( - std::shared_ptr descriptor) { - wgpu::ShaderSourceWGSL wgsl_desc{}; - wgpu::ShaderModuleDescriptor sm_desc{}; - Convertor conv; - if (!conv(wgsl_desc.code, descriptor->code) || - !conv(sm_desc.label, descriptor->label)) { - return {}; - } - sm_desc.nextInChain = &wgsl_desc; - if (descriptor->code.find('\0') != std::string::npos) { - auto mod = _instance.CreateErrorShaderModule( - &sm_desc, "The WGSL shader contains an illegal character '\\0'"); - return std::make_shared(mod, _async, sm_desc.label.data); - } - auto module = _instance.CreateShaderModule(&sm_desc); - return std::make_shared(module, _async, - descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createRenderPipeline( - std::shared_ptr descriptor) { - wgpu::RenderPipelineDescriptor desc{}; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("Error with GPURenderPipelineDescriptor"); - } - // assert(desc.fragment != nullptr && "Fragment state must not be null"); - auto renderPipeline = _instance.CreateRenderPipeline(&desc); - return std::make_shared(renderPipeline, - descriptor->label.value_or("")); -} - -std::shared_ptr -GPUDevice::createBindGroup(std::shared_ptr descriptor) { - Convertor conv; - wgpu::BindGroupDescriptor desc{}; - if (!conv(desc.label, descriptor->label) || - !conv(desc.layout, descriptor->layout) || - !conv(desc.entries, desc.entryCount, descriptor->entries)) { - throw std::runtime_error( - "GPUBindGroup::createBindGroup(): Error with GPUBindGroupDescriptor"); - } - auto bindGroup = _instance.CreateBindGroup(&desc); - return std::make_shared(bindGroup, - descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createSampler( - std::optional> descriptor) { - wgpu::SamplerDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUDevice::createSampler(): Error with " - "GPUSamplerDescriptor"); - } - auto sampler = _instance.CreateSampler(&desc); - return std::make_shared( - sampler, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -std::shared_ptr GPUDevice::createComputePipeline( - std::shared_ptr descriptor) { - wgpu::ComputePipelineDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUDevice::createComputePipeline(): Error with " - "GPUComputePipelineDescriptor"); - } - auto computePipeline = _instance.CreateComputePipeline(&desc); - return std::make_shared(computePipeline, - descriptor->label.value_or("")); -} - -std::shared_ptr -GPUDevice::createQuerySet(std::shared_ptr descriptor) { - wgpu::QuerySetDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUDevice::createQuerySet(): Error with " - "GPUQuerySetDescriptor"); - } - auto querySet = _instance.CreateQuerySet(&desc); - return std::make_shared(querySet, - descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createRenderBundleEncoder( - std::shared_ptr descriptor) { - Convertor conv; - - wgpu::RenderBundleEncoderDescriptor desc{}; - if (!conv(desc.label, descriptor->label) || - !conv(desc.colorFormats, desc.colorFormatCount, - descriptor->colorFormats) || - !conv(desc.depthStencilFormat, descriptor->depthStencilFormat) || - !conv(desc.sampleCount, descriptor->sampleCount) || - !conv(desc.depthReadOnly, descriptor->depthReadOnly) || - !conv(desc.stencilReadOnly, descriptor->stencilReadOnly)) { - return {}; - } - return std::make_shared( - _instance.CreateRenderBundleEncoder(&desc), - descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createBindGroupLayout( - std::shared_ptr descriptor) { - Convertor conv; - - wgpu::BindGroupLayoutDescriptor desc{}; - if (!conv(desc.label, descriptor->label) || - !conv(desc.entries, desc.entryCount, descriptor->entries)) { - return {}; - } - return std::make_shared( - _instance.CreateBindGroupLayout(&desc), descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::createPipelineLayout( - std::shared_ptr descriptor) { - Convertor conv; - - wgpu::PipelineLayoutDescriptor desc{}; - if (!conv(desc.label, descriptor->label) || - !conv(desc.bindGroupLayouts, desc.bindGroupLayoutCount, - descriptor->bindGroupLayouts)) { - return {}; - } - return std::make_shared( - _instance.CreatePipelineLayout(&desc), descriptor->label.value_or("")); -} - -std::shared_ptr GPUDevice::importExternalTexture( - std::shared_ptr descriptor) { - // The import / begin-access / descriptor-build logic, plus the matching - // EndAccess, all live on GPUExternalTexture so the begin/end lifecycle stays - // in one translation unit (see GPUExternalTexture.cpp). - return GPUExternalTexture::Create(_instance, std::move(descriptor)); -} - -std::shared_ptr GPUDevice::importSharedTextureMemory( - std::shared_ptr descriptor) { - if (!descriptor || descriptor->handle == 0) { - throw std::runtime_error( - "GPUDevice::importSharedTextureMemory(): handle must be a non-null " - "native buffer pointer (from Skia.NativeBuffer.MakeFromImage)"); - } - void *bufferPtr = - reinterpret_cast(static_cast(descriptor->handle)); - std::string label = descriptor->label.value_or(""); - - auto memory = importNativeBufferAsSharedTextureMemory( - _instance, bufferPtr, label, /*outWidth=*/nullptr, /*outHeight=*/nullptr); - if (memory == nullptr) { - throw std::runtime_error( - "GPUDevice::importSharedTextureMemory(): ImportSharedTextureMemory " - "returned null - is the 'shared-texture-memory-iosurface' (Apple) or " - "'shared-texture-memory-ahardware-buffer' (Android) feature enabled on " - "the device?"); - } - return std::make_shared(std::move(memory), - std::move(label)); -} - -std::shared_ptr GPUDevice::importSharedFence( - std::shared_ptr descriptor) { - if (!descriptor || descriptor->handle == nullptr) { - throw std::runtime_error("GPUDevice::importSharedFence(): handle must be a " - "non-null native handle"); - } - - wgpu::SharedFenceDescriptor desc{}; - std::string label = descriptor->label.value_or(""); - if (!label.empty()) { - desc.label = wgpu::StringView(label.c_str(), label.size()); - } - - // The chained platform descriptor must outlive the synchronous - // ImportSharedFence() below; declare them all and chain the matching one. - wgpu::SharedFenceMTLSharedEventDescriptor mtlDesc{}; - wgpu::SharedFenceSyncFDDescriptor syncFdDesc{}; - wgpu::SharedFenceVkSemaphoreOpaqueFDDescriptor vkFdDesc{}; - - const std::string &type = descriptor->type; - if (type == "mtl-shared-event") { - // handle is an id pointer. - mtlDesc.sharedEvent = descriptor->handle; - desc.nextInChain = &mtlDesc; - } else if (type == "sync-fd") { - // handle is an OS file descriptor. - syncFdDesc.handle = - static_cast(reinterpret_cast(descriptor->handle)); - desc.nextInChain = &syncFdDesc; - } else if (type == "vk-semaphore-opaque-fd") { - vkFdDesc.handle = - static_cast(reinterpret_cast(descriptor->handle)); - desc.nextInChain = &vkFdDesc; - } else { - throw std::runtime_error( - "GPUDevice::importSharedFence(): unsupported fence type '" + type + - "' (expected 'mtl-shared-event', 'sync-fd' or " - "'vk-semaphore-opaque-fd')"); - } - - auto fence = _instance.ImportSharedFence(&desc); - if (fence == nullptr) { - throw std::runtime_error( - "GPUDevice::importSharedFence(): ImportSharedFence returned null - is " - "the matching 'shared-fence-*' feature enabled on the device?"); - } - return std::make_shared(std::move(fence), std::move(label)); -} - -async::AsyncTaskHandle GPUDevice::createComputePipelineAsync( - jsi::Runtime &runtime, - std::shared_ptr descriptor) { - wgpu::ComputePipelineDescriptor desc{}; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUDevice::createComputePipeline(): Error with " - "GPUComputePipelineDescriptor"); - } - - auto label = std::string( - descriptor->label.has_value() ? descriptor->label.value() : ""); - auto pipelineHolder = std::make_shared(nullptr, label); - - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask([device = _instance, desc, descriptor, - pipelineHolder]( - const async::AsyncTaskHandle::ResolveFunction - &resolve, - const async::AsyncTaskHandle::RejectFunction - &reject) { - (void)descriptor; - device.CreateComputePipelineAsync( - &desc, wgpu::CallbackMode::AllowProcessEvents, - [pipelineHolder, resolve, - reject](wgpu::CreatePipelineAsyncStatus status, - wgpu::ComputePipeline pipeline, wgpu::StringView msg) { - if (status == wgpu::CreatePipelineAsyncStatus::Success && pipeline) { - pipelineHolder->_instance = pipeline; - resolve([pipelineHolder](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, pipelineHolder); - }); - } else { - std::string error = msg.length - ? std::string(msg.data, msg.length) - : "Failed to create compute pipeline"; - reject(std::move(error)); - } - }); - }); -} - -async::AsyncTaskHandle GPUDevice::createRenderPipelineAsync( - jsi::Runtime &runtime, - std::shared_ptr descriptor) { - wgpu::RenderPipelineDescriptor desc{}; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error( - "GPUDevice::createRenderPipelineAsync(): Error with " - "GPURenderPipelineDescriptor"); - } - - auto label = std::string( - descriptor->label.has_value() ? descriptor->label.value() : ""); - auto pipelineHolder = std::make_shared(nullptr, label); - - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask([device = _instance, desc, descriptor, - pipelineHolder]( - const async::AsyncTaskHandle::ResolveFunction - &resolve, - const async::AsyncTaskHandle::RejectFunction - &reject) { - (void)descriptor; - device.CreateRenderPipelineAsync( - &desc, wgpu::CallbackMode::AllowProcessEvents, - [pipelineHolder, resolve, - reject](wgpu::CreatePipelineAsyncStatus status, - wgpu::RenderPipeline pipeline, wgpu::StringView msg) { - if (status == wgpu::CreatePipelineAsyncStatus::Success && pipeline) { - pipelineHolder->_instance = pipeline; - resolve([pipelineHolder](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, pipelineHolder); - }); - } else { - std::string error = msg.length ? std::string(msg.data, msg.length) - : "Failed to create render pipeline"; - reject(std::move(error)); - } - }); - }); -} - -void GPUDevice::pushErrorScope(wgpu::ErrorFilter filter) { - _instance.PushErrorScope(filter); -} - -async::AsyncTaskHandle GPUDevice::popErrorScope(jsi::Runtime &runtime) { - auto device = _instance; - - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask([device]( - const async::AsyncTaskHandle::ResolveFunction - &resolve, - const async::AsyncTaskHandle::RejectFunction - &reject) { - device.PopErrorScope( - wgpu::CallbackMode::AllowProcessEvents, - [resolve, reject](wgpu::PopErrorScopeStatus status, - wgpu::ErrorType type, wgpu::StringView message) { - if (status == wgpu::PopErrorScopeStatus::Error || - status == wgpu::PopErrorScopeStatus::CallbackCancelled) { - reject("PopErrorScope failed"); - return; - } - - std::string messageString = - message.length ? std::string(message.data, message.length) : ""; - - switch (type) { - case wgpu::ErrorType::NoError: - resolve([](jsi::Runtime &runtime) mutable { - return jsi::Value::null(); - }); - break; - case wgpu::ErrorType::Validation: { - auto error = std::make_shared(messageString); - resolve([error](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, error); - }); - break; - } - case wgpu::ErrorType::OutOfMemory: { - auto error = std::make_shared(messageString); - resolve([error](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, error); - }); - break; - } - case wgpu::ErrorType::Internal: - case wgpu::ErrorType::Unknown: { - auto error = std::make_shared(messageString); - resolve([error](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, error); - }); - break; - } - default: - reject("Unhandled GPU error type"); - return; - } - }); - }); -} - -std::unordered_set GPUDevice::getFeatures() { - wgpu::SupportedFeatures supportedFeatures; - _instance.GetFeatures(&supportedFeatures); - std::unordered_set result; - for (size_t i = 0; i < supportedFeatures.featureCount; ++i) { - auto feature = supportedFeatures.features[i]; - std::string name; - convertEnumToJSUnion(feature, &name); - result.insert(name); - } - return result; -} - -async::AsyncTaskHandle GPUDevice::getLost() { - // Held across the whole body: the postTask callback below runs synchronously - // on this (JS) thread and touches the same _lost* fields, so it must not - // re-lock. notifyDeviceLost() takes the same lock from its (possibly worker) - // thread. - std::lock_guard lock(_lostMutex); - if (_lostHandle.has_value()) { - return *_lostHandle; - } - - if (_lostSettled && _lostInfo) { - return _async->postTask( - [info = _lostInfo]( - const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction & /*reject*/) { - resolve([info](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, info); - }); - }, - /*keepPumping=*/false); - } - - auto handle = _async->postTask( - [this](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction & /*reject*/) { - if (_lostSettled && _lostInfo) { - resolve([info = _lostInfo](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, info); - }); - return; - } - - // Resolved later from notifyDeviceLost(). - _lostResolve = resolve; - }, - /*keepPumping=*/false); - - _lostHandle = handle; - return handle; -} -void GPUDevice::addEventListener(std::string type, jsi::Function callback) { - std::lock_guard lock(_listenersMutex); - auto sharedCallback = std::make_shared(std::move(callback)); - _eventListeners[type].push_back(sharedCallback); -} - -void GPUDevice::removeEventListener(std::string type, jsi::Function callback) { - std::lock_guard lock(_listenersMutex); - auto it = _eventListeners.find(type); - if (it != _eventListeners.end()) { - auto &listeners = it->second; - // Remove the last listener of this type (simple approach since we can't - // easily compare jsi::Function objects) - if (!listeners.empty()) { - listeners.pop_back(); - } - } -} - -void GPUDevice::notifyUncapturedError(GPUErrorVariant error) { - // Dawn can surface an uncaptured error from any ProcessEvents pump (a worklet - // runtime sharing this instance may pump it on the wrong thread). Marshal to - // the owning runtime's JS thread via its CallInvoker before touching JSI. The - // invoker is wired only for the main JS runtime, so a device created on a - // worklet runtime does not deliver uncaptured errors to JS (best-effort; see - // the Threading model). - auto invoker = _async ? _async->callInvoker() : nullptr; - if (!invoker) { - return; - } - auto self = shared_from_this(); - invoker->invokeAsync([self, error = std::move(error)]() mutable { - self->deliverUncapturedError(std::move(error)); - }); -} - -void GPUDevice::deliverUncapturedError(GPUErrorVariant error) { - auto runtime = getCreationRuntime(); - if (runtime == nullptr) { - return; - } - - std::vector> listeners; - { - std::lock_guard lock(_listenersMutex); - auto it = _eventListeners.find("uncapturederror"); - if (it != _eventListeners.end()) { - listeners = it->second; - } - } - - if (listeners.empty()) { - return; - } - - // Create the event object - auto event = std::make_shared(std::move(error)); - auto eventValue = GPUUncapturedErrorEvent::create(*runtime, event); - - // Call all listeners - for (const auto &listener : listeners) { - try { - listener->call(*runtime, eventValue); - } catch (const std::exception &e) { - fprintf(stderr, "Error in uncapturederror listener: %s\n", e.what()); - } - } -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUDevice.h b/packages/skia/cpp/rnwgpu/api/GPUDevice.h deleted file mode 100644 index f0e18556eb..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUDevice.h +++ /dev/null @@ -1,258 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUUncapturedErrorEvent.h" - -#include "GPUBindGroup.h" -#include "GPUBindGroupLayout.h" -#include "GPUBuffer.h" -#include "GPUCommandEncoder.h" -#include "GPUComputePipeline.h" -#include "GPUDeviceLostInfo.h" -#include "GPUError.h" -#include "GPUExternalTexture.h" -#include "GPUPipelineLayout.h" -#include "GPUQuerySet.h" -#include "GPUQueue.h" -#include "GPURenderBundleEncoder.h" -#include "GPURenderPipeline.h" -#include "GPUSampler.h" -#include "GPUShaderModule.h" -#include "GPUSharedFence.h" -#include "GPUSharedTextureMemory.h" -#include "GPUSupportedLimits.h" -#include "GPUTexture.h" -#include "descriptors/GPUBindGroupDescriptor.h" -#include "descriptors/GPUBindGroupLayoutDescriptor.h" -#include "descriptors/GPUBufferDescriptor.h" -#include "descriptors/GPUCommandEncoderDescriptor.h" -#include "descriptors/GPUComputePipelineDescriptor.h" -#include "descriptors/GPUExternalTextureDescriptor.h" -#include "descriptors/GPUPipelineLayoutDescriptor.h" -#include "descriptors/GPUQuerySetDescriptor.h" -#include "descriptors/GPURenderBundleEncoderDescriptor.h" -#include "descriptors/GPURenderPipelineDescriptor.h" -#include "descriptors/GPUSamplerDescriptor.h" -#include "descriptors/GPUShaderModuleDescriptor.h" -#include "descriptors/GPUSharedFenceDescriptor.h" -#include "descriptors/GPUSharedTextureMemoryDescriptor.h" -#include "descriptors/GPUTextureDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -// Forward declaration -class GPUDevice; - -// Static registry to map wgpu::Device handles to GPUDevice instances -class GPUDeviceRegistry { -public: - static GPUDeviceRegistry &getInstance() { - static GPUDeviceRegistry instance; - return instance; - } - - void registerDevice(WGPUDevice handle, GPUDevice *device) { - std::lock_guard lock(_mutex); - _devices[handle] = device; - } - - void unregisterDevice(WGPUDevice handle) { - std::lock_guard lock(_mutex); - _devices.erase(handle); - } - - GPUDevice *getDevice(WGPUDevice handle) { - std::lock_guard lock(_mutex); - auto it = _devices.find(handle); - return it != _devices.end() ? it->second : nullptr; - } - -private: - GPUDeviceRegistry() = default; - std::mutex _mutex; - std::map _devices; -}; - -class GPUDevice : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUDevice"; - - explicit GPUDevice(wgpu::Device instance, - std::shared_ptr async, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _async(async), - _label(label) { - // Register this device in the global registry - GPUDeviceRegistry::getInstance().registerDevice(_instance.Get(), this); - } - - ~GPUDevice() { - // Unregister from the global registry - GPUDeviceRegistry::getInstance().unregisterDevice(_instance.Get()); - } - -public: - std::string getBrand() { return CLASS_NAME; } - - void destroy(); - std::shared_ptr - createBuffer(std::shared_ptr descriptor); - std::shared_ptr - createTexture(std::shared_ptr descriptor); - std::shared_ptr createSampler( - std::optional> descriptor); - std::shared_ptr importExternalTexture( - std::shared_ptr descriptor); - std::shared_ptr importSharedTextureMemory( - std::shared_ptr descriptor); - std::shared_ptr - importSharedFence(std::shared_ptr descriptor); - std::shared_ptr createBindGroupLayout( - std::shared_ptr descriptor); - std::shared_ptr - createPipelineLayout(std::shared_ptr descriptor); - std::shared_ptr - createBindGroup(std::shared_ptr descriptor); - std::shared_ptr - createShaderModule(std::shared_ptr descriptor); - std::shared_ptr createComputePipeline( - std::shared_ptr descriptor); - std::shared_ptr - createRenderPipeline(std::shared_ptr descriptor); - async::AsyncTaskHandle createComputePipelineAsync( - jsi::Runtime &runtime, - std::shared_ptr descriptor); - async::AsyncTaskHandle createRenderPipelineAsync( - jsi::Runtime &runtime, - std::shared_ptr descriptor); - std::shared_ptr createCommandEncoder( - std::optional> descriptor); - std::shared_ptr createRenderBundleEncoder( - std::shared_ptr descriptor); - std::shared_ptr - createQuerySet(std::shared_ptr descriptor); - void pushErrorScope(wgpu::ErrorFilter filter); - async::AsyncTaskHandle popErrorScope(jsi::Runtime &runtime); - - std::unordered_set getFeatures(); - std::shared_ptr getLimits(); - std::shared_ptr getQueue(); - async::AsyncTaskHandle getLost(); - void notifyDeviceLost(wgpu::DeviceLostReason reason, std::string message); - void forceLossForTesting(); - - // Event listener methods - void addEventListener(std::string type, jsi::Function callback); - void removeEventListener(std::string type, jsi::Function callback); - void notifyUncapturedError(GPUErrorVariant error); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUDevice::getBrand); - installMethod(runtime, prototype, "destroy", &GPUDevice::destroy); - installMethod(runtime, prototype, "createBuffer", &GPUDevice::createBuffer); - installMethod(runtime, prototype, "createTexture", - &GPUDevice::createTexture); - installMethod(runtime, prototype, "createSampler", - &GPUDevice::createSampler); - installMethod(runtime, prototype, "importExternalTexture", - &GPUDevice::importExternalTexture); - installMethod(runtime, prototype, "importSharedTextureMemory", - &GPUDevice::importSharedTextureMemory); - installMethod(runtime, prototype, "importSharedFence", - &GPUDevice::importSharedFence); - installMethod(runtime, prototype, "createBindGroupLayout", - &GPUDevice::createBindGroupLayout); - installMethod(runtime, prototype, "createPipelineLayout", - &GPUDevice::createPipelineLayout); - installMethod(runtime, prototype, "createBindGroup", - &GPUDevice::createBindGroup); - installMethod(runtime, prototype, "createShaderModule", - &GPUDevice::createShaderModule); - installMethod(runtime, prototype, "createComputePipeline", - &GPUDevice::createComputePipeline); - installMethod(runtime, prototype, "createRenderPipeline", - &GPUDevice::createRenderPipeline); - installMethodWithRuntime(runtime, prototype, "createComputePipelineAsync", - &GPUDevice::createComputePipelineAsync); - installMethodWithRuntime(runtime, prototype, "createRenderPipelineAsync", - &GPUDevice::createRenderPipelineAsync); - installMethod(runtime, prototype, "createCommandEncoder", - &GPUDevice::createCommandEncoder); - installMethod(runtime, prototype, "createRenderBundleEncoder", - &GPUDevice::createRenderBundleEncoder); - installMethod(runtime, prototype, "createQuerySet", - &GPUDevice::createQuerySet); - installMethod(runtime, prototype, "pushErrorScope", - &GPUDevice::pushErrorScope); - installMethodWithRuntime(runtime, prototype, "popErrorScope", - &GPUDevice::popErrorScope); - installGetter(runtime, prototype, "features", &GPUDevice::getFeatures); - installGetter(runtime, prototype, "limits", &GPUDevice::getLimits); - installGetter(runtime, prototype, "queue", &GPUDevice::getQueue); - installGetter(runtime, prototype, "lost", &GPUDevice::getLost); - installGetterSetter(runtime, prototype, "label", &GPUDevice::getLabel, - &GPUDevice::setLabel); - installMethod(runtime, prototype, "forceLossForTesting", - &GPUDevice::forceLossForTesting); - installMethod(runtime, prototype, "addEventListener", - &GPUDevice::addEventListener); - installMethod(runtime, prototype, "removeEventListener", - &GPUDevice::removeEventListener); - } - - inline const wgpu::Device get() { return _instance; } - -private: - friend class GPUAdapter; - - // Runs the uncapturederror listeners on the creation runtime's JS thread. - // Invoked from notifyUncapturedError via the main CallInvoker. - void deliverUncapturedError(GPUErrorVariant error); - - wgpu::Device _instance; - std::shared_ptr _async; - std::string _label; - // Guards the device-lost state below. In the ProcessEvents model both - // notifyDeviceLost() (fired by Dawn during ProcessEvents) and getLost() run - // on the owning runtime's own thread, but device destruction can also trigger - // notifyDeviceLost() synchronously, so the mutex keeps these fields safe. - std::mutex _lostMutex; - std::optional _lostHandle; - std::shared_ptr _lostInfo; - bool _lostSettled = false; - std::optional _lostResolve; - - // Event listeners storage - std::mutex _listenersMutex; - std::map>> - _eventListeners; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp b/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp deleted file mode 100644 index 51f31aa397..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "GPUDeviceLostInfo.h" -#include - -namespace rnwgpu { -wgpu::DeviceLostReason getReason(); -std::string getMessage(); -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.h b/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.h deleted file mode 100644 index 63550fd95d..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUDeviceLostInfo.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUDeviceLostInfo : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUDeviceLostInfo"; - - explicit GPUDeviceLostInfo(wgpu::DeviceLostReason reason, std::string message) - : NativeObject(CLASS_NAME), _reason(reason), _message(message) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - wgpu::DeviceLostReason getReason() { return _reason; } - std::string getMessage() { return _message; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUDeviceLostInfo::getBrand); - installGetter(runtime, prototype, "reason", &GPUDeviceLostInfo::getReason); - installGetter(runtime, prototype, "message", - &GPUDeviceLostInfo::getMessage); - } - -private: - wgpu::DeviceLostReason _reason; - std::string _message; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUError.h b/packages/skia/cpp/rnwgpu/api/GPUError.h deleted file mode 100644 index 93140a2595..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUError.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUError : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUError"; - - explicit GPUError(std::string message) - : NativeObject(CLASS_NAME), _message(std::move(message)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - std::string getMessage() { return _message; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUError::getBrand); - installGetter(runtime, prototype, "message", &GPUError::getMessage); - } - -protected: - // Protected constructor for subclasses - GPUError(const char *className, std::string message) - : NativeObject(className), _message(std::move(message)) {} - - std::string _message; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUExtent3D.h b/packages/skia/cpp/rnwgpu/api/GPUExtent3D.h deleted file mode 100644 index 68281c6c03..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUExtent3D.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include - -#include "jsi/JSIConverter.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -struct GPUExtent3D { - double width; - double height = 1; - double depthOrArrayLayers = 1; -}; - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - if (arg.getObject(runtime).isArray(runtime)) { - auto array = arg.getObject(runtime).asArray(runtime); - auto size = array.size(runtime); - if (size == 0) { - throw std::runtime_error( - "Expected an array of size >1 for GPUTExtent3D"); - } - if (size > 0) { - result->width = array.getValueAtIndex(runtime, 0).asNumber(); - } - if (size > 1) { - result->height = array.getValueAtIndex(runtime, 1).asNumber(); - } - if (size > 2) { - result->depthOrArrayLayers = - array.getValueAtIndex(runtime, 2).asNumber(); - } - } else { - auto object = arg.getObject(runtime); - if (object.hasProperty(runtime, "width")) { - result->width = object.getProperty(runtime, "width").asNumber(); - } else { - throw std::runtime_error("Property GPUTExtent3D::width is required"); - } - if (object.hasProperty(runtime, "height")) { - result->height = object.getProperty(runtime, "height").asNumber(); - } - if (object.hasProperty(runtime, "depthOrArrayLayers")) { - result->depthOrArrayLayers = - object.getProperty(runtime, "depthOrArrayLayers").asNumber(); - } - } - } else { - throw std::runtime_error("Expected an object for GPUTExtent3D"); - } - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - // No conversions here - return jsi::Value::null(); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.cpp b/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.cpp deleted file mode 100644 index 131b826f9a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "GPUExternalTexture.h" - -#include -#include -#include -#include - -#include "NativeBufferUtils.h" -#include "descriptors/GPUExternalTextureDescriptor.h" - -namespace rnwgpu { - -// Identity gamut (same primaries) as a 3x3 column-major matrix. -static const float kIdentityGamutMatrix[9] = { - 1.0f, 0.0f, 0.0f, // - 0.0f, 1.0f, 0.0f, // - 0.0f, 0.0f, 1.0f, // -}; - -// Identity transfer (y = x). The native buffers produced by Skia's NativeBuffer -// API are single-plane BGRA/RGBA already in the render target's color space, so -// no conversion is wanted. Dawn dereferences the transfer-function arrays -// unconditionally (ComputeExternalTextureParams), so these must be non-null. -static const float kIdentityTransferParams[7] = { - 1.0f, // G - 1.0f, // A - 0.0f, // B - 0.0f, // C - 0.0f, // D - 0.0f, // E - 0.0f, // F -}; - -// Map a rotation in degrees (0 / 90 / 180 / 270) to Dawn's enum. Anything that -// isn't a clean multiple of 90 snaps to the nearest quadrant; Dawn only -// supports those four steps for external textures. -static wgpu::ExternalTextureRotation toExternalTextureRotation(double degrees) { - int quadrant = static_cast(std::lround(degrees / 90.0)); - quadrant = ((quadrant % 4) + 4) % 4; - switch (quadrant) { - case 1: - return wgpu::ExternalTextureRotation::Rotate90Degrees; - case 2: - return wgpu::ExternalTextureRotation::Rotate180Degrees; - case 3: - return wgpu::ExternalTextureRotation::Rotate270Degrees; - default: - return wgpu::ExternalTextureRotation::Rotate0Degrees; - } -} - -std::shared_ptr GPUExternalTexture::Create( - wgpu::Device device, - std::shared_ptr descriptor) { - if (!descriptor || descriptor->source == 0) { - throw std::runtime_error( - "GPUExternalTexture::Create(): descriptor.source (a native buffer " - "pointer from Skia.NativeBuffer.MakeFromImage) is required"); - } - void *bufferPtr = - reinterpret_cast(static_cast(descriptor->source)); - std::string label = descriptor->label.value_or("external-texture"); - - // 1. Import the native buffer as SharedTextureMemory and read its dimensions. - uint32_t width = 0; - uint32_t height = 0; - wgpu::SharedTextureMemory memory = importNativeBufferAsSharedTextureMemory( - device, bufferPtr, label, &width, &height); - if (memory == nullptr) { - throw std::runtime_error( - "GPUExternalTexture::Create(): ImportSharedTextureMemory returned " - "null"); - } - - // 2. Create the texture from the surface (Dawn picks the single-plane - // BGRA/RGBA format). - auto texture = memory.CreateTexture(); - if (texture == nullptr) { - throw std::runtime_error( - "GPUExternalTexture::Create(): CreateTexture returned null"); - } - - // 3. Begin access. The matching EndAccess runs when the GPUExternalTexture is - // destroyed (explicitly via destroy() or at GC). - wgpu::SharedTextureMemoryBeginAccessDescriptor begin{}; - begin.initialized = true; - begin.concurrentRead = false; -#if defined(__ANDROID__) - // Dawn's Vulkan backend requires the acquired VkImageLayout to be chained. - // UNDEFINED (= 0) on both ends is the canonical "no prior GPU producer" - // pattern (matches GPUSharedTextureMemory::beginAccess). - wgpu::SharedTextureMemoryVkImageLayoutBeginState vkBegin{}; - vkBegin.oldLayout = 0; - vkBegin.newLayout = 0; - begin.nextInChain = &vkBegin; -#endif - if (!memory.BeginAccess(texture, &begin)) { - throw std::runtime_error( - "GPUExternalTexture::Create(): BeginAccess failed"); - } - - // 4. Single-plane view (the whole BGRA/RGBA surface). - auto plane0 = texture.CreateView(); - - // 5. Build the ExternalTextureDescriptor. The surface is already RGB in the - // target color space, so pass it through with identity transfer/gamut. - wgpu::ExternalTextureDescriptor extDesc{}; - if (!label.empty()) { - extDesc.label = wgpu::StringView(label.c_str(), label.size()); - } - extDesc.plane0 = plane0; - extDesc.gamutConversionMatrix = kIdentityGamutMatrix; - extDesc.srcTransferFunctionParameters = kIdentityTransferParams; - extDesc.dstTransferFunctionParameters = kIdentityTransferParams; - extDesc.cropOrigin = {0, 0}; - extDesc.cropSize = {width, height}; - extDesc.apparentSize = {width, height}; - extDesc.mirrored = descriptor->mirrored.value_or(false); - extDesc.rotation = - toExternalTextureRotation(descriptor->rotation.value_or(0)); - - auto external = device.CreateExternalTexture(&extDesc); - if (external == nullptr) { - wgpu::SharedTextureMemoryEndAccessState state{}; -#if defined(__ANDROID__) - wgpu::SharedTextureMemoryVkImageLayoutEndState vkEnd{}; - state.nextInChain = &vkEnd; -#endif - (void)memory.EndAccess(texture, &state); - throw std::runtime_error( - "GPUExternalTexture::Create(): CreateExternalTexture returned null"); - } - - return std::make_shared( - std::move(external), std::move(memory), std::move(texture), - std::move(label)); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.h b/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.h deleted file mode 100644 index 7264d91d3b..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUExternalTexture.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -struct GPUExternalTextureDescriptor; - -class GPUExternalTexture : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUExternalTexture"; - - // Import a native buffer (via descriptor.source, a CVPixelBufferRef / - // AHardwareBuffer* from Skia's NativeBuffer API) as a GPUExternalTexture on - // `device`: imports the native surface as SharedTextureMemory, begins access, - // and wraps the resulting wgpu::ExternalTexture together with the resources - // whose lifetime it owns. The matching EndAccess runs in destroy() / the - // destructor. Defined in GPUExternalTexture.cpp. - static std::shared_ptr - Create(wgpu::Device device, - std::shared_ptr descriptor); - - // Construct from an already-built wgpu::ExternalTexture plus the underlying - // shared-memory resources we need to keep alive. The wrapper takes ownership - // of the SharedTextureMemory + Texture and calls EndAccess on destruction so - // the producer (the native buffer's surface) can reclaim it. - GPUExternalTexture(wgpu::ExternalTexture instance, - wgpu::SharedTextureMemory memory, wgpu::Texture texture, - std::string label) - : NativeObject(CLASS_NAME), _instance(std::move(instance)), - _memory(std::move(memory)), _texture(std::move(texture)), - _label(std::move(label)) {} - - ~GPUExternalTexture() override { destroy(); } - -public: - std::string getBrand() { return CLASS_NAME; } - - // End the shared-memory access window and release the underlying resources. - // Idempotent: safe to call more than once, and the destructor calls it as a - // garbage-collection fallback. Call it right after the queue.submit() that - // sampled this texture (never before): a GPUExternalTexture's access window - // is owned by this wrapper's lifetime, not by submit, so without an explicit - // destroy() the producer's surface stays claimed until GC runs. EndAccess is - // the designed post-submit call: Dawn keeps the texture alive for in-flight - // GPU work via the fences it returns. - void destroy() { - if (_memory && _texture) { - wgpu::SharedTextureMemoryEndAccessState state{}; -#if defined(__ANDROID__) - // Dawn's Vulkan backend requires the released VkImageLayout to be chained - // (matches BeginAccess in GPUExternalTexture::Create). - wgpu::SharedTextureMemoryVkImageLayoutEndState vkEnd{}; - state.nextInChain = &vkEnd; -#endif - (void)_memory.EndAccess(_texture, &state); - } - _texture = nullptr; - _memory = nullptr; - } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUExternalTexture::getBrand); - installGetterSetter(runtime, prototype, "label", - &GPUExternalTexture::getLabel, - &GPUExternalTexture::setLabel); - installMethod(runtime, prototype, "destroy", &GPUExternalTexture::destroy); - } - - inline const wgpu::ExternalTexture get() { return _instance; } - -private: - wgpu::ExternalTexture _instance; - wgpu::SharedTextureMemory _memory; - wgpu::Texture _texture; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUFeatures.h b/packages/skia/cpp/rnwgpu/api/GPUFeatures.h deleted file mode 100644 index 514bdb59b0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUFeatures.h +++ /dev/null @@ -1,203 +0,0 @@ -#pragma once - -#include - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -static void convertEnumToJSUnion(wgpu::FeatureName inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::FeatureName::DepthClipControl: - *outUnion = "depth-clip-control"; - break; - case wgpu::FeatureName::Depth32FloatStencil8: - *outUnion = "depth32float-stencil8"; - break; - case wgpu::FeatureName::TimestampQuery: - *outUnion = "timestamp-query"; - break; - case wgpu::FeatureName::TextureCompressionBC: - *outUnion = "texture-compression-bc"; - break; - case wgpu::FeatureName::TextureCompressionETC2: - *outUnion = "texture-compression-etc2"; - break; - case wgpu::FeatureName::TextureCompressionASTC: - *outUnion = "texture-compression-astc"; - break; - case wgpu::FeatureName::IndirectFirstInstance: - *outUnion = "indirect-first-instance"; - break; - case wgpu::FeatureName::ShaderF16: - *outUnion = "shader-f16"; - break; - case wgpu::FeatureName::RG11B10UfloatRenderable: - *outUnion = "rg11b10ufloat-renderable"; - break; - case wgpu::FeatureName::BGRA8UnormStorage: - *outUnion = "bgra8unorm-storage"; - break; - case wgpu::FeatureName::Float32Filterable: - *outUnion = "float32-filterable"; - break; - case wgpu::FeatureName::Subgroups: - *outUnion = "subgroups"; - break; - case wgpu::FeatureName::DawnInternalUsages: - *outUnion = "dawn-internal-usages"; - break; - case wgpu::FeatureName::DawnMultiPlanarFormats: - *outUnion = "dawn-multi-planar-formats"; - break; - case wgpu::FeatureName::DawnNative: - *outUnion = "dawn-native"; - break; - case wgpu::FeatureName::ChromiumExperimentalTimestampQueryInsidePasses: - *outUnion = "chromium-experimental-timestamp-query-inside-passes"; - break; - case wgpu::FeatureName::ImplicitDeviceSynchronization: - *outUnion = "implicit-device-synchronization"; - break; - case wgpu::FeatureName::TransientAttachments: - *outUnion = "transient-attachments"; - break; - case wgpu::FeatureName::MSAARenderToSingleSampled: - *outUnion = "msaa-render-to-single-sampled"; - break; - case wgpu::FeatureName::DualSourceBlending: - *outUnion = "dual-source-blending"; - break; - case wgpu::FeatureName::D3D11MultithreadProtected: - *outUnion = "d3d11-multithread-protected"; - break; - case wgpu::FeatureName::ANGLETextureSharing: - *outUnion = "angle-texture-sharing"; - break; - case wgpu::FeatureName::ChromiumExperimentalSubgroupMatrix: - *outUnion = "chromium-experimental-subgroups-matrix"; - break; - case wgpu::FeatureName::PixelLocalStorageCoherent: - *outUnion = "pixel-local-storage-coherent"; - break; - case wgpu::FeatureName::PixelLocalStorageNonCoherent: - *outUnion = "pixel-local-storage-non-coherent"; - break; - case wgpu::FeatureName::Unorm16TextureFormats: - *outUnion = "unorm16-texture-formats"; - break; - case wgpu::FeatureName::MultiPlanarFormatExtendedUsages: - *outUnion = "multi-planar-format-extended-usages"; - break; - case wgpu::FeatureName::MultiPlanarFormatP010: - *outUnion = "multi-planar-format-p010"; - break; - case wgpu::FeatureName::HostMappedPointer: - *outUnion = "host-mapped-pointer"; - break; - case wgpu::FeatureName::MultiPlanarRenderTargets: - *outUnion = "multi-planar-render-targets"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv12a: - *outUnion = "multi-planar-format-nv12a"; - break; - case wgpu::FeatureName::FramebufferFetch: - *outUnion = "framebuffer-fetch"; - break; - case wgpu::FeatureName::BufferMapExtendedUsages: - *outUnion = "buffer-map-extended-usages"; - break; - case wgpu::FeatureName::AdapterPropertiesMemoryHeaps: - *outUnion = "adapter-properties-memory-heaps"; - break; - case wgpu::FeatureName::AdapterPropertiesD3D: - *outUnion = "adapter-properties-d3d"; - break; - case wgpu::FeatureName::AdapterPropertiesVk: - *outUnion = "adapter-properties-vk"; - break; - case wgpu::FeatureName::DawnFormatCapabilities: - *outUnion = "format-capabilities"; - break; - case wgpu::FeatureName::DawnDrmFormatCapabilities: - *outUnion = "drm-format-capabilities"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv16: - *outUnion = "multi-planar-format-nv16"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv24: - *outUnion = "multi-planar-format-nv24"; - break; - case wgpu::FeatureName::MultiPlanarFormatP210: - *outUnion = "multi-planar-format-p210"; - break; - case wgpu::FeatureName::MultiPlanarFormatP410: - *outUnion = "multi-planar-format-p410"; - break; - case wgpu::FeatureName::SharedTextureMemoryVkDedicatedAllocation: - *outUnion = "shared-texture-memory-vk-dedicated-allocation"; - break; - case wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer: - *outUnion = "shared-texture-memory-ahardware-buffer"; - break; - case wgpu::FeatureName::SharedTextureMemoryDmaBuf: - *outUnion = "shared-texture-memory-dma-buf"; - break; - case wgpu::FeatureName::SharedTextureMemoryOpaqueFD: - *outUnion = "shared-texture-memory-opaque-fd"; - break; - case wgpu::FeatureName::SharedTextureMemoryZirconHandle: - *outUnion = "shared-texture-memory-zircon-handle"; - break; - case wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle: - *outUnion = "shared-texture-memory-dxgi-shared-handle"; - break; - case wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D: - *outUnion = "shared-texture-memory-d3d11-texture2d"; - break; - case wgpu::FeatureName::SharedTextureMemoryIOSurface: - *outUnion = "shared-texture-memory-iosurface"; - break; - case wgpu::FeatureName::SharedTextureMemoryEGLImage: - *outUnion = "shared-texture-memory-egl-image"; - break; - case wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD: - *outUnion = "shared-fence-vk-semaphore-opaque-fd"; - break; - case wgpu::FeatureName::SharedFenceSyncFD: - *outUnion = "shared-fence-vk-semaphore-sync-fd"; - break; - case wgpu::FeatureName::SharedFenceVkSemaphoreZirconHandle: - *outUnion = "shared-fence-vk-semaphore-zircon-handle"; - break; - case wgpu::FeatureName::SharedFenceDXGISharedHandle: - *outUnion = "shared-fence-dxgi-shared-handle"; - break; - case wgpu::FeatureName::SharedFenceMTLSharedEvent: - *outUnion = "shared-fence-mtl-shared-event"; - break; - case wgpu::FeatureName::SharedBufferMemoryD3D12Resource: - *outUnion = "shared-buffer-memory-d3d12-resource"; - break; - case wgpu::FeatureName::StaticSamplers: - *outUnion = "static-samplers"; - break; - case wgpu::FeatureName::YCbCrVulkanSamplers: - *outUnion = "ycbcr-vulkan-samplers"; - break; - case wgpu::FeatureName::ShaderModuleCompilationOptions: - *outUnion = "shader-module-compilation-options"; - break; - case wgpu::FeatureName::DawnLoadResolveTexture: - *outUnion = "dawn-load-resolve-texture"; - break; - default: - fprintf(stderr, "Unknown feature name %d\n", static_cast(inEnum)); - *outUnion = ""; - } -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUInternalError.h b/packages/skia/cpp/rnwgpu/api/GPUInternalError.h deleted file mode 100644 index 54e0e25e84..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUInternalError.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUInternalError : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUInternalError"; - - explicit GPUInternalError(std::string message) - : NativeObject(CLASS_NAME), _message(std::move(message)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - std::string getMessage() { return _message; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUInternalError::getBrand); - installGetter(runtime, prototype, "message", &GPUInternalError::getMessage); - } - -private: - std::string _message; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUOrigin2D.h b/packages/skia/cpp/rnwgpu/api/GPUOrigin2D.h deleted file mode 100644 index dd9a9875b9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUOrigin2D.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include - -#include "jsi/JSIConverter.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -struct GPUOrigin2D { - double x = 0; - double y = 0; -}; - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - if (arg.getObject(runtime).isArray(runtime)) { - auto array = arg.getObject(runtime).asArray(runtime); - auto size = array.size(runtime); - if (size == 0) { - throw std::runtime_error( - "Expected an array of size >1 for GPUTExtent2D"); - } - if (size > 0) { - result->x = array.getValueAtIndex(runtime, 0).asNumber(); - } - if (size > 1) { - result->y = array.getValueAtIndex(runtime, 1).asNumber(); - } - } else { - auto object = arg.getObject(runtime); - if (object.hasProperty(runtime, "x")) { - result->x = object.getProperty(runtime, "x").asNumber(); - } - if (object.hasProperty(runtime, "y")) { - result->y = object.getProperty(runtime, "y").asNumber(); - } - } - } else { - throw std::runtime_error("Expected an object for GPUOrigin3D"); - } - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - // No conversions here - return jsi::Value::null(); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUOrigin3D.h b/packages/skia/cpp/rnwgpu/api/GPUOrigin3D.h deleted file mode 100644 index b0100f6c2f..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUOrigin3D.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include - -#include "jsi/JSIConverter.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -struct GPUOrigin3D { - double x = 0; - double y = 0; - double z = 0; -}; - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - if (arg.getObject(runtime).isArray(runtime)) { - auto array = arg.getObject(runtime).asArray(runtime); - auto size = array.size(runtime); - if (size == 0) { - throw std::runtime_error( - "Expected an array of size >1 for GPUTExtent3D"); - } - if (size > 0) { - result->x = array.getValueAtIndex(runtime, 0).asNumber(); - } - if (size > 1) { - result->y = array.getValueAtIndex(runtime, 1).asNumber(); - } - if (size > 2) { - result->z = array.getValueAtIndex(runtime, 2).asNumber(); - } - } else { - auto object = arg.getObject(runtime); - if (object.hasProperty(runtime, "x")) { - result->x = object.getProperty(runtime, "x").asNumber(); - } - if (object.hasProperty(runtime, "y")) { - result->y = object.getProperty(runtime, "y").asNumber(); - } - if (object.hasProperty(runtime, "z")) { - result->z = object.getProperty(runtime, "z").asNumber(); - } - } - } else { - throw std::runtime_error("Expected an object for GPUOrigin3D"); - } - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - // No conversions here - return jsi::Value::null(); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUOutOfMemoryError.h b/packages/skia/cpp/rnwgpu/api/GPUOutOfMemoryError.h deleted file mode 100644 index 5772396e6a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUOutOfMemoryError.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUOutOfMemoryError : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUOutOfMemoryError"; - - explicit GPUOutOfMemoryError(std::string message) - : NativeObject(CLASS_NAME), _message(std::move(message)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - std::string getMessage() { return _message; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPUOutOfMemoryError::getBrand); - installGetter(runtime, prototype, "message", - &GPUOutOfMemoryError::getMessage); - } - -private: - std::string _message; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUPipelineLayout.h b/packages/skia/cpp/rnwgpu/api/GPUPipelineLayout.h deleted file mode 100644 index a5b06d4d23..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUPipelineLayout.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUPipelineLayout : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUPipelineLayout"; - - explicit GPUPipelineLayout(wgpu::PipelineLayout instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUPipelineLayout::getBrand); - installGetterSetter(runtime, prototype, "label", - &GPUPipelineLayout::getLabel, - &GPUPipelineLayout::setLabel); - } - - inline const wgpu::PipelineLayout get() { return _instance; } - -private: - wgpu::PipelineLayout _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUQuerySet.cpp b/packages/skia/cpp/rnwgpu/api/GPUQuerySet.cpp deleted file mode 100644 index 32d1df4fb9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUQuerySet.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "GPUQuerySet.h" - -namespace rnwgpu { - -void GPUQuerySet::destroy() { _instance.Destroy(); } - -wgpu::QueryType GPUQuerySet::getType() { return _instance.GetType(); } - -uint32_t GPUQuerySet::getCount() { return _instance.GetCount(); } - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPUQuerySet.h b/packages/skia/cpp/rnwgpu/api/GPUQuerySet.h deleted file mode 100644 index 5027b53ab2..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUQuerySet.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUQuerySet : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUQuerySet"; - - explicit GPUQuerySet(wgpu::QuerySet instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - void destroy(); - - wgpu::QueryType getType(); - uint32_t getCount(); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUQuerySet::getBrand); - installMethod(runtime, prototype, "destroy", &GPUQuerySet::destroy); - installGetter(runtime, prototype, "type", &GPUQuerySet::getType); - installGetter(runtime, prototype, "count", &GPUQuerySet::getCount); - installGetterSetter(runtime, prototype, "label", &GPUQuerySet::getLabel, - &GPUQuerySet::setLabel); - } - - 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; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUQueue.cpp b/packages/skia/cpp/rnwgpu/api/GPUQueue.cpp deleted file mode 100644 index d16029d653..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUQueue.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "GPUQueue.h" - -#include -#include -#include -#include - -#include "Convertors.h" - -namespace rnwgpu { - -struct BufferSource { - void *data; - size_t size; // in bytes - size_t bytesPerElement; // 1 for ArrayBuffers -}; - -void GPUQueue::submit( - std::vector> commandBuffers) { - std::vector bufs(commandBuffers.size()); - for (size_t i = 0; i < commandBuffers.size(); i++) { - bufs[i] = commandBuffers[i]->get(); - } - Convertor conv; - uint32_t bufs_size; - if (!conv(bufs_size, bufs.size())) { - return; - } - _instance.Submit(bufs_size, bufs.data()); -} - -void GPUQueue::writeBuffer(std::shared_ptr buffer, - uint64_t bufferOffset, - std::shared_ptr data, - std::optional dataOffsetElements, - std::optional sizeElements) { - wgpu::Buffer buf = buffer->get(); - BufferSource src{.data = data->_data, - .size = data->_size, - .bytesPerElement = data->_bytesPerElement}; - - // 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)) { - throw std::runtime_error("dataOffset is larger than data's size."); - return; - } - uint64_t dataOffset = dataOffsetElements.value_or(0) * src.bytesPerElement; - src.data = reinterpret_cast(src.data) + dataOffset; - src.size -= dataOffset; - - // Size defaults to dataSize - dataOffset. Instead of computing in elements, - // we directly use it in bytes, and convert the provided value, if any, in - // bytes. - uint64_t size64 = static_cast(src.size); - if (sizeElements.has_value()) { - if (sizeElements.value() > - std::numeric_limits::max() / src.bytesPerElement) { - throw std::runtime_error("size overflows."); - return; - } - size64 = sizeElements.value() * src.bytesPerElement; - } - - if (size64 > static_cast(src.size)) { - throw std::runtime_error("size + dataOffset is larger than data's size."); - return; - } - - if (size64 % 4 != 0) { - throw std::runtime_error("size is not a multiple of 4 bytes."); - - return; - } - - assert(size64 <= std::numeric_limits::max()); - _instance.WriteBuffer(buf, bufferOffset, src.data, - static_cast(size64)); -} - -async::AsyncTaskHandle GPUQueue::onSubmittedWorkDone(jsi::Runtime &runtime) { - auto queue = _instance; - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask( - [queue](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { - queue.OnSubmittedWorkDone( - wgpu::CallbackMode::AllowProcessEvents, - [resolve, reject](wgpu::QueueWorkDoneStatus status, - wgpu::StringView message) { - if (status == wgpu::QueueWorkDoneStatus::Success) { - resolve(nullptr); - } else { - std::string error = - message.length ? std::string(message.data, message.length) - : "Queue work did not complete successfully"; - reject(std::move(error)); - } - }); - }); -} - -void GPUQueue::copyExternalImageToTexture( - std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr size) { - if (!source || source->source == nullptr) { - throw std::runtime_error("GPUQueue::copyExternalImageToTexture(): " - "source.source (ImageBitmap) is required"); - } - // ImageBitmap holds decoded, row-major RGBA8 pixels. We upload them with - // WriteTexture (a CPU staging copy) rather than a GPU blit; that is enough - // for the common "decode an image, sample it" path and avoids needing a - // source GPUTexture. - const auto &pixels = source->source->data(); - auto width = static_cast(source->source->getWidth()); - auto height = static_cast(source->source->getHeight()); - if (pixels.empty() || width == 0 || height == 0) { - throw std::runtime_error("GPUQueue::copyExternalImageToTexture(): " - "ImageBitmap has no pixels (was it closed?)"); - } - auto bytesPerPixel = static_cast( - pixels.size() / (static_cast(width) * height)); - uint32_t rowSize = bytesPerPixel * width; - - wgpu::TexelCopyTextureInfo dst{}; - wgpu::TexelCopyBufferLayout layout{}; - wgpu::Extent3D sz{}; - Convertor conv; - auto dataLayout = std::make_shared( - GPUImageDataLayout{std::optional{0.0}, - std::optional{static_cast(rowSize)}, - std::optional{static_cast(height)}}); - if (!conv(dst.aspect, destination->aspect) || - !conv(dst.mipLevel, destination->mipLevel) || - !conv(dst.origin, destination->origin) || - !conv(dst.texture, destination->texture) || !conv(layout, dataLayout) || - !conv(sz, size)) { - throw std::runtime_error( - "Invalid input for GPUQueue::copyExternalImageToTexture()"); - } - - if (source->flipY.value_or(false)) { - // Flip rows so the image is uploaded bottom-up (matches the WebGPU - // copyExternalImageToTexture flipY semantics). - std::vector flippedData(pixels.size()); - for (uint32_t row = 0; row < height; ++row) { - std::memcpy(flippedData.data() + (height - 1 - row) * rowSize, - pixels.data() + row * rowSize, rowSize); - } - _instance.WriteTexture(&dst, flippedData.data(), flippedData.size(), - &layout, &sz); - } else { - _instance.WriteTexture(&dst, pixels.data(), pixels.size(), &layout, &sz); - } -} - -void GPUQueue::writeTexture(std::shared_ptr destination, - std::shared_ptr data, - std::shared_ptr dataLayout, - std::shared_ptr size) { - wgpu::TexelCopyTextureInfo dst{}; - wgpu::TexelCopyBufferLayout layout{}; - wgpu::Extent3D sz{}; - Convertor conv; - if (!conv(dst, destination) || // - !conv(layout, dataLayout) || // - !conv(sz, size)) { - throw std::runtime_error("Invalid input for GPUQueue::writeTexture()"); - } - - _instance.WriteTexture(&dst, data->_data, data->_size, &layout, &sz); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUQueue.h b/packages/skia/cpp/rnwgpu/api/GPUQueue.h deleted file mode 100644 index afff8c870d..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUQueue.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBuffer.h" -#include "GPUCommandBuffer.h" -#include "GPUExtent3D.h" -#include "descriptors/GPUImageCopyExternalImage.h" -#include "descriptors/GPUImageCopyTexture.h" -#include "descriptors/GPUImageCopyTextureTagged.h" -#include "descriptors/GPUImageDataLayout.h" -#include "rnwgpu/ArrayBuffer.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUQueue : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUQueue"; - - explicit GPUQueue(wgpu::Queue instance, - std::shared_ptr async, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _async(async), - _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - void submit(std::vector> commandBuffers); - async::AsyncTaskHandle onSubmittedWorkDone(jsi::Runtime &runtime); - void writeBuffer(std::shared_ptr buffer, uint64_t bufferOffset, - std::shared_ptr data, - std::optional dataOffsetElements, - std::optional sizeElements); - void writeTexture(std::shared_ptr destination, - std::shared_ptr data, - std::shared_ptr dataLayout, - std::shared_ptr size); - void copyExternalImageToTexture( - std::shared_ptr source, - std::shared_ptr destination, - std::shared_ptr copySize); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUQueue::getBrand); - installMethod(runtime, prototype, "submit", &GPUQueue::submit); - installMethodWithRuntime(runtime, prototype, "onSubmittedWorkDone", - &GPUQueue::onSubmittedWorkDone); - installMethod(runtime, prototype, "writeBuffer", &GPUQueue::writeBuffer); - installMethod(runtime, prototype, "writeTexture", &GPUQueue::writeTexture); - installMethod(runtime, prototype, "copyExternalImageToTexture", - &GPUQueue::copyExternalImageToTexture); - installGetterSetter(runtime, prototype, "label", &GPUQueue::getLabel, - &GPUQueue::setLabel); - } - - inline const wgpu::Queue get() { return _instance; } - -private: - wgpu::Queue _instance; - std::shared_ptr _async; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderBundle.h b/packages/skia/cpp/rnwgpu/api/GPURenderBundle.h deleted file mode 100644 index 1d5af275d0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderBundle.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPURenderBundle : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPURenderBundle"; - - explicit GPURenderBundle(wgpu::RenderBundle instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPURenderBundle::getBrand); - installGetterSetter(runtime, prototype, "label", &GPURenderBundle::getLabel, - &GPURenderBundle::setLabel); - } - - inline const wgpu::RenderBundle get() { return _instance; } - -private: - wgpu::RenderBundle _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.cpp b/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.cpp deleted file mode 100644 index ece7257ea9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "GPURenderBundleEncoder.h" - -#include -#include - -#include "Convertors.h" - -namespace rnwgpu { - -std::shared_ptr GPURenderBundleEncoder::finish( - std::optional> descriptor) { - wgpu::RenderBundleDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPURenderBundleEncoder.finish(): couldn't get " - "GPURenderBundleDescriptor"); - } - auto bundle = _instance.Finish(&desc); - return std::make_shared( - bundle, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -void GPURenderBundleEncoder::setPipeline( - std::shared_ptr pipeline) { - _instance.SetPipeline(pipeline->get()); -} - -void GPURenderBundleEncoder::draw(uint32_t vertexCount, - std::optional instanceCount, - std::optional firstVertex, - std::optional firstInstance) { - _instance.Draw(vertexCount, instanceCount.value_or(1), - firstVertex.value_or(0), firstInstance.value_or(0)); -} - -void GPURenderBundleEncoder::setVertexBuffer( - uint32_t slot, - std::variant> buffer, - std::optional offset, std::optional size) { - Convertor conv; - - wgpu::Buffer b{}; - uint64_t s = wgpu::kWholeSize; - if (!conv(b, buffer) || !conv(s, size)) { - return; - } - _instance.SetVertexBuffer(slot, b, offset.value_or(0), s); -} - -void GPURenderBundleEncoder::setBindGroup( - uint32_t groupIndex, - std::variant> bindGroup, - std::optional> dynamicOffsets) { - auto dynOffsets = dynamicOffsets.value_or(std::vector()); - if (dynOffsets.size() == 0) { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(groupIndex, nullptr, 0, nullptr); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(groupIndex, group->get(), 0, nullptr); - } - } else { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(groupIndex, nullptr, dynOffsets.size(), - dynamicOffsets->data()); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(groupIndex, group->get(), dynOffsets.size(), - dynamicOffsets->data()); - } - } -} - -void GPURenderBundleEncoder::setIndexBuffer(std::shared_ptr buffer, - wgpu::IndexFormat indexFormat, - std::optional offset, - std::optional size) { - Convertor conv; - - wgpu::Buffer b{}; - wgpu::IndexFormat f{}; - uint64_t o = 0; - uint64_t s = wgpu::kWholeSize; - if (!conv(b, buffer) || // - !conv(f, indexFormat) || // - !conv(o, offset) || // - !conv(s, size)) { - return; - } - - _instance.SetIndexBuffer(b, f, o, s); -} - -void GPURenderBundleEncoder::drawIndexed( - uint32_t indexCount, std::optional instanceCount, - std::optional firstIndex, std::optional baseVertex, - std::optional firstInstance) { - _instance.DrawIndexed(indexCount, instanceCount.value_or(1), - firstIndex.value_or(0), baseVertex.value_or(0), - firstInstance.value_or(0)); -} - -void GPURenderBundleEncoder::pushDebugGroup(std::string groupLabel) { - _instance.PushDebugGroup(groupLabel.c_str()); -} - -void GPURenderBundleEncoder::popDebugGroup() { _instance.PopDebugGroup(); } - -void GPURenderBundleEncoder::insertDebugMarker(std::string markerLabel) { - _instance.InsertDebugMarker(markerLabel.c_str()); -} -void GPURenderBundleEncoder::drawIndirect( - std::shared_ptr indirectBuffer, uint64_t indirectOffset) { - Convertor conv; - wgpu::Buffer b{}; - if (!conv(b, indirectBuffer)) { - return; - } - _instance.DrawIndirect(b, indirectOffset); -} -void GPURenderBundleEncoder::drawIndexedIndirect( - std::shared_ptr indirectBuffer, uint64_t indirectOffset) { - Convertor conv; - wgpu::Buffer b{}; - if (!conv(b, indirectBuffer)) { - return; - } - _instance.DrawIndexedIndirect(b, indirectOffset); -} -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.h b/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.h deleted file mode 100644 index 3addd702b0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderBundleEncoder.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBindGroup.h" -#include "GPUBuffer.h" -#include "GPURenderBundle.h" -#include "GPURenderPipeline.h" -#include "descriptors/GPURenderBundleDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPURenderBundleEncoder : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPURenderBundleEncoder"; - - explicit GPURenderBundleEncoder(wgpu::RenderBundleEncoder instance, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr - finish(std::optional> descriptor); - void pushDebugGroup(std::string groupLabel); - void popDebugGroup(); - void insertDebugMarker(std::string markerLabel); - void setBindGroup( - uint32_t index, - std::variant> bindGroup, - std::optional> dynamicOffsets); - void setPipeline(std::shared_ptr pipeline); - void setIndexBuffer(std::shared_ptr buffer, - wgpu::IndexFormat indexFormat, - std::optional offset, - std::optional size); - void setVertexBuffer( - uint32_t slot, - std::variant> buffer, - std::optional offset, std::optional size); - void draw(uint32_t vertexCount, std::optional instanceCount, - std::optional firstVertex, - std::optional firstInstance); - void drawIndexed(uint32_t indexCount, std::optional instanceCount, - std::optional firstIndex, - std::optional baseVertex, - std::optional firstInstance); - void drawIndirect(std::shared_ptr indirectBuffer, - uint64_t indirectOffset); - void drawIndexedIndirect(std::shared_ptr indirectBuffer, - uint64_t indirectOffset); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPURenderBundleEncoder::getBrand); - installMethod(runtime, prototype, "finish", - &GPURenderBundleEncoder::finish); - installMethod(runtime, prototype, "pushDebugGroup", - &GPURenderBundleEncoder::pushDebugGroup); - installMethod(runtime, prototype, "popDebugGroup", - &GPURenderBundleEncoder::popDebugGroup); - installMethod(runtime, prototype, "insertDebugMarker", - &GPURenderBundleEncoder::insertDebugMarker); - installMethod(runtime, prototype, "setBindGroup", - &GPURenderBundleEncoder::setBindGroup); - installMethod(runtime, prototype, "setPipeline", - &GPURenderBundleEncoder::setPipeline); - installMethod(runtime, prototype, "setIndexBuffer", - &GPURenderBundleEncoder::setIndexBuffer); - installMethod(runtime, prototype, "setVertexBuffer", - &GPURenderBundleEncoder::setVertexBuffer); - installMethod(runtime, prototype, "draw", &GPURenderBundleEncoder::draw); - installMethod(runtime, prototype, "drawIndexed", - &GPURenderBundleEncoder::drawIndexed); - installMethod(runtime, prototype, "drawIndirect", - &GPURenderBundleEncoder::drawIndirect); - installMethod(runtime, prototype, "drawIndexedIndirect", - &GPURenderBundleEncoder::drawIndexedIndirect); - installGetterSetter(runtime, prototype, "label", - &GPURenderBundleEncoder::getLabel, - &GPURenderBundleEncoder::setLabel); - } - - inline const wgpu::RenderBundleEncoder get() { return _instance; } - -private: - wgpu::RenderBundleEncoder _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.cpp b/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.cpp deleted file mode 100644 index 99be1f2522..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include - -#include "Convertors.h" -#include "GPURenderPassEncoder.h" - -namespace rnwgpu { - -void GPURenderPassEncoder::end() { _instance.End(); } - -void GPURenderPassEncoder::setPipeline( - std::shared_ptr pipeline) { - _instance.SetPipeline(pipeline->get()); -} - -void GPURenderPassEncoder::draw(uint32_t vertexCount, - std::optional instanceCount, - std::optional firstVertex, - std::optional firstInstance) { - _instance.Draw(vertexCount, instanceCount.value_or(1), - firstVertex.value_or(0), firstInstance.value_or(0)); -} -void GPURenderPassEncoder::setVertexBuffer( - uint32_t slot, - std::variant> buffer, - std::optional offset, std::optional size) { - Convertor conv; - - wgpu::Buffer b{}; - uint64_t s = wgpu::kWholeSize; - if (!conv(b, buffer) || !conv(s, size)) { - return; - } - _instance.SetVertexBuffer(slot, b, offset.value_or(0), s); -} - -void GPURenderPassEncoder::setBindGroup( - uint32_t groupIndex, - std::variant> bindGroup, - std::optional> dynamicOffsets) { - auto dynOffsets = dynamicOffsets.value_or(std::vector()); - if (dynOffsets.size() == 0) { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(groupIndex, nullptr, 0, nullptr); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(groupIndex, group->get(), 0, nullptr); - } - } else { - if (std::holds_alternative(bindGroup)) { - _instance.SetBindGroup(groupIndex, nullptr, dynOffsets.size(), - dynamicOffsets->data()); - } else { - auto group = std::get>(bindGroup); - _instance.SetBindGroup(groupIndex, group->get(), dynOffsets.size(), - dynamicOffsets->data()); - } - } -} - -void GPURenderPassEncoder::setIndexBuffer(std::shared_ptr buffer, - wgpu::IndexFormat indexFormat, - std::optional offset, - std::optional size) { - Convertor conv; - - wgpu::Buffer b{}; - wgpu::IndexFormat f{}; - uint64_t o = 0; - uint64_t s = wgpu::kWholeSize; - if (!conv(b, buffer) || // - !conv(f, indexFormat) || // - !conv(o, offset) || // - !conv(s, size)) { - return; - } - - _instance.SetIndexBuffer(b, f, o, s); -} - -void GPURenderPassEncoder::endOcclusionQuery() { - _instance.EndOcclusionQuery(); -} - -void GPURenderPassEncoder::beginOcclusionQuery(uint32_t queryIndex) { - _instance.BeginOcclusionQuery(queryIndex); -} - -void GPURenderPassEncoder::drawIndexed(uint32_t indexCount, - std::optional instanceCount, - std::optional firstIndex, - std::optional baseVertex, - std::optional firstInstance) { - _instance.DrawIndexed(indexCount, instanceCount.value_or(1), - firstIndex.value_or(0), baseVertex.value_or(0), - firstInstance.value_or(0)); -} - -void GPURenderPassEncoder::executeBundles( - std::vector> bundles_in) { - Convertor conv; - - wgpu::RenderBundle *bundles = nullptr; - size_t bundleCount = 0; - if (!conv(bundles, bundleCount, bundles_in)) { - return; - } - - _instance.ExecuteBundles(bundleCount, bundles); -} - -void GPURenderPassEncoder::setScissorRect(uint32_t x, uint32_t y, - uint32_t width, uint32_t height) { - _instance.SetScissorRect(x, y, width, height); -} - -void GPURenderPassEncoder::setViewport(double x, double y, double width, - double height, double minDepth, - double maxDepth) { - _instance.SetViewport(x, y, width, height, minDepth, maxDepth); -} - -void GPURenderPassEncoder::setBlendConstant(std::shared_ptr color) { - Convertor conv; - wgpu::Color c{}; - if (!conv(c, color)) { - return; - } - _instance.SetBlendConstant(&c); -} - -void GPURenderPassEncoder::setStencilReference(uint32_t reference) { - _instance.SetStencilReference(reference); -} - -void GPURenderPassEncoder::pushDebugGroup(std::string groupLabel) { - _instance.PushDebugGroup(groupLabel.c_str()); -} - -void GPURenderPassEncoder::popDebugGroup() { _instance.PopDebugGroup(); } - -void GPURenderPassEncoder::insertDebugMarker(std::string markerLabel) { - _instance.InsertDebugMarker(markerLabel.c_str()); -} -void GPURenderPassEncoder::drawIndirect( - std::shared_ptr indirectBuffer, uint64_t indirectOffset) { - Convertor conv; - wgpu::Buffer b{}; - if (!conv(b, indirectBuffer)) { - return; - } - _instance.DrawIndirect(b, indirectOffset); -} -void GPURenderPassEncoder::drawIndexedIndirect( - std::shared_ptr indirectBuffer, uint64_t indirectOffset) { - Convertor conv; - wgpu::Buffer b{}; - if (!conv(b, indirectBuffer)) { - return; - } - _instance.DrawIndexedIndirect(b, indirectOffset); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.h b/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.h deleted file mode 100644 index b8f7d6d7bc..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderPassEncoder.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBindGroup.h" -#include "GPUBuffer.h" -#include "GPURenderBundle.h" -#include "GPURenderPipeline.h" -#include "descriptors/GPUColor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPURenderPassEncoder : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPURenderPassEncoder"; - - explicit GPURenderPassEncoder(wgpu::RenderPassEncoder instance, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - void setViewport(double x, double y, double width, double height, - double minDepth, double maxDepth); - void setScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height); - void setBlendConstant(std::shared_ptr color); - void setStencilReference(uint32_t reference); - void beginOcclusionQuery(uint32_t queryIndex); - void endOcclusionQuery(); - void executeBundles(std::vector> bundles); - void end(); - void pushDebugGroup(std::string groupLabel); - void popDebugGroup(); - void insertDebugMarker(std::string markerLabel); - void setBindGroup( - uint32_t index, - std::variant> bindGroup, - std::optional> dynamicOffsets); - void setPipeline(std::shared_ptr pipeline); - void setIndexBuffer(std::shared_ptr buffer, - wgpu::IndexFormat indexFormat, - std::optional offset, - std::optional size); - void setVertexBuffer( - uint32_t slot, - std::variant> buffer, - std::optional offset, std::optional size); - void draw(uint32_t vertexCount, std::optional instanceCount, - std::optional firstVertex, - std::optional firstInstance); - void drawIndexed(uint32_t indexCount, std::optional instanceCount, - std::optional firstIndex, - std::optional baseVertex, - std::optional firstInstance); - void drawIndirect(std::shared_ptr indirectBuffer, - uint64_t indirectOffset); - void drawIndexedIndirect(std::shared_ptr indirectBuffer, - uint64_t indirectOffset); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPURenderPassEncoder::getBrand); - installMethod(runtime, prototype, "setViewport", - &GPURenderPassEncoder::setViewport); - installMethod(runtime, prototype, "setScissorRect", - &GPURenderPassEncoder::setScissorRect); - installMethod(runtime, prototype, "setBlendConstant", - &GPURenderPassEncoder::setBlendConstant); - installMethod(runtime, prototype, "setStencilReference", - &GPURenderPassEncoder::setStencilReference); - installMethod(runtime, prototype, "beginOcclusionQuery", - &GPURenderPassEncoder::beginOcclusionQuery); - installMethod(runtime, prototype, "endOcclusionQuery", - &GPURenderPassEncoder::endOcclusionQuery); - installMethod(runtime, prototype, "executeBundles", - &GPURenderPassEncoder::executeBundles); - installMethod(runtime, prototype, "end", &GPURenderPassEncoder::end); - installMethod(runtime, prototype, "pushDebugGroup", - &GPURenderPassEncoder::pushDebugGroup); - installMethod(runtime, prototype, "popDebugGroup", - &GPURenderPassEncoder::popDebugGroup); - installMethod(runtime, prototype, "insertDebugMarker", - &GPURenderPassEncoder::insertDebugMarker); - installMethod(runtime, prototype, "setBindGroup", - &GPURenderPassEncoder::setBindGroup); - installMethod(runtime, prototype, "setPipeline", - &GPURenderPassEncoder::setPipeline); - installMethod(runtime, prototype, "setIndexBuffer", - &GPURenderPassEncoder::setIndexBuffer); - installMethod(runtime, prototype, "setVertexBuffer", - &GPURenderPassEncoder::setVertexBuffer); - installMethod(runtime, prototype, "draw", &GPURenderPassEncoder::draw); - installMethod(runtime, prototype, "drawIndexed", - &GPURenderPassEncoder::drawIndexed); - installMethod(runtime, prototype, "drawIndirect", - &GPURenderPassEncoder::drawIndirect); - installMethod(runtime, prototype, "drawIndexedIndirect", - &GPURenderPassEncoder::drawIndexedIndirect); - installGetterSetter(runtime, prototype, "label", - &GPURenderPassEncoder::getLabel, - &GPURenderPassEncoder::setLabel); - } - - inline const wgpu::RenderPassEncoder get() { return _instance; } - -private: - wgpu::RenderPassEncoder _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.cpp b/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.cpp deleted file mode 100644 index 5c9bd11531..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "GPURenderPipeline.h" - -#include - -namespace rnwgpu { - -std::shared_ptr -GPURenderPipeline::getBindGroupLayout(uint32_t groupIndex) { - auto bindGroupLayout = _instance.GetBindGroupLayout(groupIndex); - return std::make_shared(bindGroupLayout, ""); -} - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.h b/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.h deleted file mode 100644 index af3b6aa566..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPURenderPipeline.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBindGroupLayout.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPURenderPipeline : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPURenderPipeline"; - - explicit GPURenderPipeline(wgpu::RenderPipeline instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr getBindGroupLayout(uint32_t index); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPURenderPipeline::getBrand); - installMethod(runtime, prototype, "getBindGroupLayout", - &GPURenderPipeline::getBindGroupLayout); - installGetterSetter(runtime, prototype, "label", - &GPURenderPipeline::getLabel, - &GPURenderPipeline::setLabel); - } - - 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; - friend class GPUDevice; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSampler.h b/packages/skia/cpp/rnwgpu/api/GPUSampler.h deleted file mode 100644 index 19774fd259..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSampler.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUSampler : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUSampler"; - - explicit GPUSampler(wgpu::Sampler instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUSampler::getBrand); - installGetterSetter(runtime, prototype, "label", &GPUSampler::getLabel, - &GPUSampler::setLabel); - } - - inline const wgpu::Sampler get() { return _instance; } - -private: - wgpu::Sampler _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUShaderModule.cpp b/packages/skia/cpp/rnwgpu/api/GPUShaderModule.cpp deleted file mode 100644 index bf5d6b1e07..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUShaderModule.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "GPUShaderModule.h" - -#include -#include - -#include "jsi/JSIConverter.h" - -namespace rnwgpu { - -async::AsyncTaskHandle -GPUShaderModule::getCompilationInfo(jsi::Runtime &runtime) { - auto module = _instance; - - // Post to the CALLING runtime's context so the promise settles on the - // thread that requested it (see GPUBuffer::mapAsync). - auto context = - async::RuntimeContext::getOrCreate(runtime, _async->instance()); - return context->postTask( - [module](const async::AsyncTaskHandle::ResolveFunction &resolve, - const async::AsyncTaskHandle::RejectFunction &reject) { - auto result = std::make_shared(); - module.GetCompilationInfo( - wgpu::CallbackMode::AllowProcessEvents, - [result, resolve, - reject](wgpu::CompilationInfoRequestStatus status, - const wgpu::CompilationInfo *compilationInfo) { - if (status != wgpu::CompilationInfoRequestStatus::Success || - compilationInfo == nullptr) { - reject("Failed to get compilation info"); - return; - } - - result->_messages.reserve(compilationInfo->messageCount); - for (size_t i = 0; i < compilationInfo->messageCount; ++i) { - const auto &wgpuMessage = compilationInfo->messages[i]; - GPUCompilationMessageData message; - message.message = - wgpuMessage.message.length ? wgpuMessage.message.data : ""; - message.type = wgpuMessage.type; - message.lineNum = wgpuMessage.lineNum; - message.linePos = wgpuMessage.linePos; - message.offset = wgpuMessage.offset; - message.length = wgpuMessage.length; - result->_messages.push_back(std::move(message)); - } - - resolve([result = - std::move(result)](jsi::Runtime &runtime) mutable { - return JSIConverter>::toJSI( - runtime, result); - }); - }); - }); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUShaderModule.h b/packages/skia/cpp/rnwgpu/api/GPUShaderModule.h deleted file mode 100644 index 3b2abc1eb1..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUShaderModule.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "rnwgpu/async/AsyncTaskHandle.h" -#include "rnwgpu/async/RuntimeContext.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUCompilationInfo.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUShaderModule : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUShaderModule"; - - explicit GPUShaderModule(wgpu::ShaderModule instance, - std::shared_ptr async, - std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _async(async), - _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - async::AsyncTaskHandle getCompilationInfo(jsi::Runtime &runtime); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUShaderModule::getBrand); - installMethodWithRuntime(runtime, prototype, "getCompilationInfo", - &GPUShaderModule::getCompilationInfo); - installGetterSetter(runtime, prototype, "label", &GPUShaderModule::getLabel, - &GPUShaderModule::setLabel); - } - - 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; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSharedFence.cpp b/packages/skia/cpp/rnwgpu/api/GPUSharedFence.cpp deleted file mode 100644 index 7465612615..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSharedFence.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "GPUSharedFence.h" - -#include -#include - -#if defined(__ANDROID__) -#include -#endif - -namespace rnwgpu { - -namespace { - -// Kebab-case names matching the shared-fence-* feature strings (see Unions.h / -// GPUFeatures.h). -std::string sharedFenceTypeToString(wgpu::SharedFenceType type) { - switch (type) { - case wgpu::SharedFenceType::MTLSharedEvent: - return "mtl-shared-event"; - case wgpu::SharedFenceType::SyncFD: - return "sync-fd"; - case wgpu::SharedFenceType::VkSemaphoreOpaqueFD: - return "vk-semaphore-opaque-fd"; - case wgpu::SharedFenceType::VkSemaphoreZirconHandle: - return "vk-semaphore-zircon-handle"; - case wgpu::SharedFenceType::DXGISharedHandle: - return "dxgi-shared-handle"; - case wgpu::SharedFenceType::EGLSync: - return "egl-sync"; - default: - return ""; - } -} - -} // namespace - -jsi::Value GPUSharedFence::exportInfo(jsi::Runtime &runtime, const jsi::Value &, - const jsi::Value *, size_t) { - wgpu::SharedFenceExportInfo info{}; - uint64_t handle = 0; - -#if defined(__APPLE__) - // Apple: the handle is an id pointer. - wgpu::SharedFenceMTLSharedEventExportInfo mtlInfo{}; - info.nextInChain = &mtlInfo; - _instance.ExportInfo(&info); - handle = reinterpret_cast(mtlInfo.sharedEvent); -#elif defined(__ANDROID__) - // Android: the handle is an OS file descriptor (sync_fd). Dawn's ExportInfo - // returns a BORROWED fd: it is owned by the SharedFence and closed when the - // fence is destroyed. This exported handle is documented as caller-owned (the - // caller must close() it), so dup() it. Without the dup the same fd is closed - // twice (once by the caller and once by Dawn on fence destruction), tripping - // Android's fdsan (double-close abort). - wgpu::SharedFenceSyncFDExportInfo fdInfo{}; - info.nextInChain = &fdInfo; - _instance.ExportInfo(&info); - int exportedFd = fdInfo.handle >= 0 - ? ::fcntl(fdInfo.handle, F_DUPFD_CLOEXEC, 0) - : fdInfo.handle; - handle = static_cast(static_cast(exportedFd)); -#else - // react-native-skia only targets Apple (Metal) and Android (Vulkan). On any - // other platform there is no native handle convention to expose, so fail - // loudly rather than handing back a meaningless handle of 0. - throw jsi::JSError(runtime, - "GPUSharedFence::export(): unsupported platform (only " - "Apple/Metal and Android/Vulkan are supported)"); -#endif - - jsi::Object result(runtime); - result.setProperty( - runtime, "type", - jsi::String::createFromUtf8(runtime, sharedFenceTypeToString(info.type))); - result.setProperty(runtime, "handle", - jsi::BigInt::fromUint64(runtime, handle)); - return result; -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSharedFence.h b/packages/skia/cpp/rnwgpu/api/GPUSharedFence.h deleted file mode 100644 index d3bbe6cb03..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSharedFence.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -// Wraps a wgpu::SharedFence: a native GPU sync primitive (id on -// Apple, sync-fd / VkSemaphore on Android). -class GPUSharedFence : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUSharedFence"; - - explicit GPUSharedFence(wgpu::SharedFence instance, std::string label) - : NativeObject(CLASS_NAME), _instance(std::move(instance)), - _label(std::move(label)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - // export() -> { type, handle }: exposes the native handle (as a BigInt) so - // app code can wait on or signal the fence. The caller owns the returned - // handle (e.g. an exported sync-fd must be close()d). - jsi::Value exportInfo(jsi::Runtime &runtime, const jsi::Value &thisVal, - const jsi::Value *args, size_t count); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUSharedFence::getBrand); - installMethod(runtime, prototype, "export", &GPUSharedFence::exportInfo); - installGetterSetter(runtime, prototype, "label", &GPUSharedFence::getLabel, - &GPUSharedFence::setLabel); - } - - inline wgpu::SharedFence get() { return _instance; } - -private: - wgpu::SharedFence _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp b/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp deleted file mode 100644 index 53cf66138b..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "GPUSharedTextureMemory.h" - -#include -#include -#include -#include -#include -#include - -#include "Convertors.h" - -namespace rnwgpu { - -std::shared_ptr GPUSharedTextureMemory::createTexture( - std::optional> descriptor) { - if (!descriptor.has_value() || descriptor.value() == nullptr) { - auto texture = _instance.CreateTexture(); - // The texture aliases the shared memory; it doesn't own GPU allocation, so - // it doesn't report memory pressure. - return std::make_shared(texture, "", false); - } - - wgpu::TextureDescriptor desc{}; - Convertor conv; - if (!conv(desc, descriptor.value())) { - throw std::runtime_error( - "GPUSharedTextureMemory::createTexture(): Error with " - "GPUTextureDescriptor"); - } - auto texture = _instance.CreateTexture(&desc); - return std::make_shared( - texture, descriptor.value()->label.value_or(""), false); -} - -void GPUSharedTextureMemory::beginAccess( - std::shared_ptr texture, bool initialized, - std::optional>> fences) { - if (!texture) { - throw std::runtime_error( - "GPUSharedTextureMemory::beginAccess(): texture is null"); - } - wgpu::SharedTextureMemoryBeginAccessDescriptor desc{}; - desc.initialized = initialized; - desc.concurrentRead = false; - - // Built in lockstep so fenceCount covers both arrays, and kept in locals so - // the raw pointers outlive the synchronous BeginAccess() below. - std::vector rawFences; - std::vector values; - if (fences.has_value()) { - for (const auto &state : *fences) { - if (state && state->fence) { - rawFences.push_back(state->fence->get()); - values.push_back(state->signaledValue); - } - } - } - if (!rawFences.empty()) { - desc.fenceCount = rawFences.size(); - desc.fences = rawFences.data(); - desc.signaledValues = values.data(); - } else { - desc.fenceCount = 0; - desc.fences = nullptr; - desc.signaledValues = nullptr; - } - -#if defined(__ANDROID__) - // Dawn's Vulkan backend (AHardwareBuffer) validates that the begin-access - // descriptor chains a SharedTextureMemoryVkImageLayoutBeginState specifying - // the VkImageLayout to acquire the image into. UNDEFINED (= 0) on both ends - // is the canonical "no prior GPU producer" pattern: Dawn performs an - // external-queue acquire from VK_QUEUE_FAMILY_EXTERNAL which preserves the - // AHB contents, then transitions to whatever layout the texture's actual - // usage requires. - wgpu::SharedTextureMemoryVkImageLayoutBeginState vkLayout{}; - vkLayout.oldLayout = 0; - vkLayout.newLayout = 0; - desc.nextInChain = &vkLayout; -#endif - - auto status = _instance.BeginAccess(texture->get(), &desc); - if (!status) { - throw std::runtime_error("GPUSharedTextureMemory::beginAccess() failed"); - } -} - -jsi::Value GPUSharedTextureMemory::endAccess(jsi::Runtime &runtime, - const jsi::Value &, - const jsi::Value *args, - size_t count) { - if (count < 1 || !args[0].isObject()) { - throw jsi::JSError( - runtime, "GPUSharedTextureMemory::endAccess(): expected (texture)"); - } - auto texture = GPUTexture::fromValue(runtime, args[0]); - - wgpu::SharedTextureMemoryEndAccessState state{}; - -#if defined(__ANDROID__) - // Dawn's Vulkan backend writes the released old/new VkImageLayouts back into - // a chained SharedTextureMemoryVkImageLayoutEndState; validation requires - // the chain even when the caller doesn't read the values. - wgpu::SharedTextureMemoryVkImageLayoutEndState vkLayout{}; - state.nextInChain = &vkLayout; -#endif - - auto status = _instance.EndAccess(texture->get(), &state); - if (!status) { - throw jsi::JSError(runtime, "GPUSharedTextureMemory::endAccess() failed"); - } - - // Copy each wgpu::SharedFence (ref-counted) into its own GPUSharedFence - // wrapper before `state` is destroyed. - jsi::Array fences(runtime, state.fenceCount); - for (size_t i = 0; i < state.fenceCount; i++) { - wgpu::SharedFence fence = state.fences[i]; - auto wrapper = std::make_shared(std::move(fence), ""); - jsi::Object entry(runtime); - entry.setProperty(runtime, "fence", - GPUSharedFence::create(runtime, std::move(wrapper))); - entry.setProperty( - runtime, "signaledValue", - jsi::BigInt::fromUint64(runtime, state.signaledValues[i])); - fences.setValueAtIndex(runtime, i, std::move(entry)); - } - - jsi::Object result(runtime); - result.setProperty(runtime, "initialized", - jsi::Value(static_cast(state.initialized))); - result.setProperty(runtime, "fences", std::move(fences)); - return result; -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.h b/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.h deleted file mode 100644 index 329b0cc605..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSharedTextureMemory.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUSharedFence.h" -#include "GPUTexture.h" -#include "descriptors/GPUSharedFenceState.h" -#include "descriptors/GPUTextureDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUSharedTextureMemory : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUSharedTextureMemory"; - - explicit GPUSharedTextureMemory(wgpu::SharedTextureMemory instance, - std::string label) - : NativeObject(CLASS_NAME), _instance(std::move(instance)), - _label(std::move(label)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr createTexture( - std::optional> descriptor); - - // Optional `fences` are wait fences: Dawn waits for each to reach its - // signaledValue before writing the surface. Throws on failure. - void beginAccess( - std::shared_ptr texture, bool initialized, - std::optional>> fences); - - // endAccess(texture) -> { initialized, fences: { fence, signaledValue }[] } - // Surfaces the fences Dawn produced for the access. Throws on failure. - jsi::Value endAccess(jsi::Runtime &runtime, const jsi::Value &thisVal, - const jsi::Value *args, size_t count); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", - &GPUSharedTextureMemory::getBrand); - installMethod(runtime, prototype, "createTexture", - &GPUSharedTextureMemory::createTexture); - installMethod(runtime, prototype, "beginAccess", - &GPUSharedTextureMemory::beginAccess); - installMethod(runtime, prototype, "endAccess", - &GPUSharedTextureMemory::endAccess); - installGetterSetter(runtime, prototype, "label", - &GPUSharedTextureMemory::getLabel, - &GPUSharedTextureMemory::setLabel); - } - - inline const wgpu::SharedTextureMemory get() { return _instance; } - -private: - wgpu::SharedTextureMemory _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.cpp b/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.cpp deleted file mode 100644 index c2178b5c24..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "GPUSupportedLimits.h" - -namespace rnwgpu { - -double GPUSupportedLimits::getMaxTextureDimension1D() { - return _instance.maxTextureDimension1D; -} - -double GPUSupportedLimits::getMaxTextureDimension2D() { - return _instance.maxTextureDimension2D; -} - -double GPUSupportedLimits::getMaxTextureDimension3D() { - return _instance.maxTextureDimension3D; -} - -double GPUSupportedLimits::getMaxTextureArrayLayers() { - return _instance.maxTextureArrayLayers; -} - -double GPUSupportedLimits::getMaxBindGroups() { - return _instance.maxBindGroups; -} - -double GPUSupportedLimits::getMaxBindGroupsPlusVertexBuffers() { - return _instance.maxBindGroupsPlusVertexBuffers; -} - -double GPUSupportedLimits::getMaxBindingsPerBindGroup() { - return _instance.maxBindingsPerBindGroup; -} - -double GPUSupportedLimits::getMaxDynamicUniformBuffersPerPipelineLayout() { - return _instance.maxDynamicUniformBuffersPerPipelineLayout; -} - -double GPUSupportedLimits::getMaxDynamicStorageBuffersPerPipelineLayout() { - return _instance.maxDynamicStorageBuffersPerPipelineLayout; -} - -double GPUSupportedLimits::getMaxSampledTexturesPerShaderStage() { - return _instance.maxSampledTexturesPerShaderStage; -} - -double GPUSupportedLimits::getMaxSamplersPerShaderStage() { - return _instance.maxSamplersPerShaderStage; -} - -double GPUSupportedLimits::getMaxStorageBuffersPerShaderStage() { - return _instance.maxStorageBuffersPerShaderStage; -} - -double GPUSupportedLimits::getMaxStorageTexturesPerShaderStage() { - return _instance.maxStorageTexturesPerShaderStage; -} - -double GPUSupportedLimits::getMaxUniformBuffersPerShaderStage() { - return _instance.maxUniformBuffersPerShaderStage; -} - -double GPUSupportedLimits::getMaxUniformBufferBindingSize() { - return _instance.maxUniformBufferBindingSize; -} - -double GPUSupportedLimits::getMaxStorageBufferBindingSize() { - return _instance.maxStorageBufferBindingSize; -} - -double GPUSupportedLimits::getMinUniformBufferOffsetAlignment() { - return _instance.minUniformBufferOffsetAlignment; -} - -double GPUSupportedLimits::getMinStorageBufferOffsetAlignment() { - return _instance.minStorageBufferOffsetAlignment; -} - -double GPUSupportedLimits::getMaxVertexBuffers() { - return _instance.maxVertexBuffers; -} - -double GPUSupportedLimits::getMaxBufferSize() { - return _instance.maxBufferSize; -} - -double GPUSupportedLimits::getMaxVertexAttributes() { - return _instance.maxVertexAttributes; -} - -double GPUSupportedLimits::getMaxVertexBufferArrayStride() { - return _instance.maxVertexBufferArrayStride; -} - -double GPUSupportedLimits::getMaxInterStageShaderVariables() { - return _instance.maxInterStageShaderVariables; -} - -double GPUSupportedLimits::getMaxColorAttachments() { - return _instance.maxColorAttachments; -} - -double GPUSupportedLimits::getMaxColorAttachmentBytesPerSample() { - return _instance.maxColorAttachmentBytesPerSample; -} - -double GPUSupportedLimits::getMaxComputeWorkgroupStorageSize() { - return _instance.maxComputeWorkgroupStorageSize; -} - -double GPUSupportedLimits::getMaxComputeInvocationsPerWorkgroup() { - return _instance.maxComputeInvocationsPerWorkgroup; -} - -double GPUSupportedLimits::getMaxComputeWorkgroupSizeX() { - return _instance.maxComputeWorkgroupSizeX; -} - -double GPUSupportedLimits::getMaxComputeWorkgroupSizeY() { - return _instance.maxComputeWorkgroupSizeY; -} - -double GPUSupportedLimits::getMaxComputeWorkgroupSizeZ() { - return _instance.maxComputeWorkgroupSizeZ; -} - -double GPUSupportedLimits::getMaxComputeWorkgroupsPerDimension() { - return _instance.maxComputeWorkgroupsPerDimension; -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.h b/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.h deleted file mode 100644 index d4f13fa02b..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUSupportedLimits.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUSupportedLimits : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUSupportedLimits"; - - explicit GPUSupportedLimits(wgpu::Limits instance) - : NativeObject(CLASS_NAME), _instance(instance) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - double getMaxTextureDimension1D(); - double getMaxTextureDimension2D(); - double getMaxTextureDimension3D(); - double getMaxTextureArrayLayers(); - double getMaxBindGroups(); - double getMaxBindGroupsPlusVertexBuffers(); - double getMaxBindingsPerBindGroup(); - double getMaxDynamicUniformBuffersPerPipelineLayout(); - double getMaxDynamicStorageBuffersPerPipelineLayout(); - double getMaxSampledTexturesPerShaderStage(); - double getMaxSamplersPerShaderStage(); - double getMaxStorageBuffersPerShaderStage(); - double getMaxStorageTexturesPerShaderStage(); - double getMaxUniformBuffersPerShaderStage(); - double getMaxUniformBufferBindingSize(); - double getMaxStorageBufferBindingSize(); - double getMinUniformBufferOffsetAlignment(); - double getMinStorageBufferOffsetAlignment(); - double getMaxVertexBuffers(); - double getMaxBufferSize(); - double getMaxVertexAttributes(); - double getMaxVertexBufferArrayStride(); - double getMaxInterStageShaderVariables(); - double getMaxColorAttachments(); - double getMaxColorAttachmentBytesPerSample(); - double getMaxComputeWorkgroupStorageSize(); - double getMaxComputeInvocationsPerWorkgroup(); - double getMaxComputeWorkgroupSizeX(); - double getMaxComputeWorkgroupSizeY(); - double getMaxComputeWorkgroupSizeZ(); - double getMaxComputeWorkgroupsPerDimension(); - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUSupportedLimits::getBrand); - installGetter(runtime, prototype, "maxTextureDimension1D", - &GPUSupportedLimits::getMaxTextureDimension1D); - installGetter(runtime, prototype, "maxTextureDimension2D", - &GPUSupportedLimits::getMaxTextureDimension2D); - installGetter(runtime, prototype, "maxTextureDimension3D", - &GPUSupportedLimits::getMaxTextureDimension3D); - installGetter(runtime, prototype, "maxTextureArrayLayers", - &GPUSupportedLimits::getMaxTextureArrayLayers); - installGetter(runtime, prototype, "maxBindGroups", - &GPUSupportedLimits::getMaxBindGroups); - installGetter(runtime, prototype, "maxBindGroupsPlusVertexBuffers", - &GPUSupportedLimits::getMaxBindGroupsPlusVertexBuffers); - installGetter(runtime, prototype, "maxBindingsPerBindGroup", - &GPUSupportedLimits::getMaxBindingsPerBindGroup); - installGetter( - runtime, prototype, "maxDynamicUniformBuffersPerPipelineLayout", - &GPUSupportedLimits::getMaxDynamicUniformBuffersPerPipelineLayout); - installGetter( - runtime, prototype, "maxDynamicStorageBuffersPerPipelineLayout", - &GPUSupportedLimits::getMaxDynamicStorageBuffersPerPipelineLayout); - installGetter(runtime, prototype, "maxSampledTexturesPerShaderStage", - &GPUSupportedLimits::getMaxSampledTexturesPerShaderStage); - installGetter(runtime, prototype, "maxSamplersPerShaderStage", - &GPUSupportedLimits::getMaxSamplersPerShaderStage); - installGetter(runtime, prototype, "maxStorageBuffersPerShaderStage", - &GPUSupportedLimits::getMaxStorageBuffersPerShaderStage); - installGetter(runtime, prototype, "maxStorageTexturesPerShaderStage", - &GPUSupportedLimits::getMaxStorageTexturesPerShaderStage); - installGetter(runtime, prototype, "maxUniformBuffersPerShaderStage", - &GPUSupportedLimits::getMaxUniformBuffersPerShaderStage); - installGetter(runtime, prototype, "maxUniformBufferBindingSize", - &GPUSupportedLimits::getMaxUniformBufferBindingSize); - installGetter(runtime, prototype, "maxStorageBufferBindingSize", - &GPUSupportedLimits::getMaxStorageBufferBindingSize); - installGetter(runtime, prototype, "minUniformBufferOffsetAlignment", - &GPUSupportedLimits::getMinUniformBufferOffsetAlignment); - installGetter(runtime, prototype, "minStorageBufferOffsetAlignment", - &GPUSupportedLimits::getMinStorageBufferOffsetAlignment); - installGetter(runtime, prototype, "maxVertexBuffers", - &GPUSupportedLimits::getMaxVertexBuffers); - installGetter(runtime, prototype, "maxBufferSize", - &GPUSupportedLimits::getMaxBufferSize); - installGetter(runtime, prototype, "maxVertexAttributes", - &GPUSupportedLimits::getMaxVertexAttributes); - installGetter(runtime, prototype, "maxVertexBufferArrayStride", - &GPUSupportedLimits::getMaxVertexBufferArrayStride); - installGetter(runtime, prototype, "maxInterStageShaderVariables", - &GPUSupportedLimits::getMaxInterStageShaderVariables); - installGetter(runtime, prototype, "maxColorAttachments", - &GPUSupportedLimits::getMaxColorAttachments); - installGetter(runtime, prototype, "maxColorAttachmentBytesPerSample", - &GPUSupportedLimits::getMaxColorAttachmentBytesPerSample); - installGetter(runtime, prototype, "maxComputeWorkgroupStorageSize", - &GPUSupportedLimits::getMaxComputeWorkgroupStorageSize); - installGetter(runtime, prototype, "maxComputeInvocationsPerWorkgroup", - &GPUSupportedLimits::getMaxComputeInvocationsPerWorkgroup); - installGetter(runtime, prototype, "maxComputeWorkgroupSizeX", - &GPUSupportedLimits::getMaxComputeWorkgroupSizeX); - installGetter(runtime, prototype, "maxComputeWorkgroupSizeY", - &GPUSupportedLimits::getMaxComputeWorkgroupSizeY); - installGetter(runtime, prototype, "maxComputeWorkgroupSizeZ", - &GPUSupportedLimits::getMaxComputeWorkgroupSizeZ); - installGetter(runtime, prototype, "maxComputeWorkgroupsPerDimension", - &GPUSupportedLimits::getMaxComputeWorkgroupsPerDimension); - } - - inline const wgpu::Limits get() { return _instance; } - -private: - wgpu::Limits _instance; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUTexture.cpp b/packages/skia/cpp/rnwgpu/api/GPUTexture.cpp deleted file mode 100644 index f1d84b99c2..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUTexture.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "GPUTexture.h" - -#include - -#include "Convertors.h" - -namespace rnwgpu { - -void GPUTexture::destroy() { _instance.Destroy(); } - -std::shared_ptr GPUTexture::createView( - std::optional> descriptor) { - wgpu::TextureViewDescriptor desc; - Convertor conv; - if (!conv(desc, descriptor)) { - throw std::runtime_error("GPUTextureView.createView(): couldn't access " - "GPUTextureViewDescriptor"); - } - auto view = _instance.CreateView(&desc); - return std::make_shared( - view, - descriptor.has_value() ? descriptor.value()->label.value_or("") : ""); -} - -uint32_t GPUTexture::getWidth() { return _instance.GetWidth(); } - -uint32_t GPUTexture::getHeight() { return _instance.GetHeight(); } - -uint32_t GPUTexture::getDepthOrArrayLayers() { - return _instance.GetDepthOrArrayLayers(); -} - -uint32_t GPUTexture::getMipLevelCount() { return _instance.GetMipLevelCount(); } - -uint32_t GPUTexture::getSampleCount() { return _instance.GetSampleCount(); } - -wgpu::TextureDimension GPUTexture::getDimension() { - return _instance.GetDimension(); -} - -wgpu::TextureFormat GPUTexture::getFormat() { return _instance.GetFormat(); } - -double GPUTexture::getUsage() { - return static_cast(_instance.GetUsage()); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUTexture.h b/packages/skia/cpp/rnwgpu/api/GPUTexture.h deleted file mode 100644 index 3902d6333f..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUTexture.h +++ /dev/null @@ -1,162 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -#include "GPUTextureView.h" -#include "descriptors/GPUTextureViewDescriptor.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUTexture : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUTexture"; - - explicit GPUTexture(wgpu::Texture instance, std::string label, - bool reportsMemoryPressure = true) - : NativeObject(CLASS_NAME), _instance(instance), _label(label), - _reportsMemoryPressure(reportsMemoryPressure) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::shared_ptr createView( - std::optional> descriptor); - void destroy(); - - uint32_t getWidth(); - uint32_t getHeight(); - uint32_t getDepthOrArrayLayers(); - uint32_t getMipLevelCount(); - uint32_t getSampleCount(); - wgpu::TextureDimension getDimension(); - wgpu::TextureFormat getFormat(); - double getUsage(); - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUTexture::getBrand); - installMethod(runtime, prototype, "createView", &GPUTexture::createView); - installMethod(runtime, prototype, "destroy", &GPUTexture::destroy); - installGetter(runtime, prototype, "width", &GPUTexture::getWidth); - installGetter(runtime, prototype, "height", &GPUTexture::getHeight); - installGetter(runtime, prototype, "depthOrArrayLayers", - &GPUTexture::getDepthOrArrayLayers); - installGetter(runtime, prototype, "mipLevelCount", - &GPUTexture::getMipLevelCount); - installGetter(runtime, prototype, "sampleCount", - &GPUTexture::getSampleCount); - installGetter(runtime, prototype, "dimension", &GPUTexture::getDimension); - installGetter(runtime, prototype, "format", &GPUTexture::getFormat); - installGetter(runtime, prototype, "usage", &GPUTexture::getUsage); - installGetterSetter(runtime, prototype, "label", &GPUTexture::getLabel, - &GPUTexture::setLabel); - } - - inline const wgpu::Texture get() { return _instance; } - - size_t getMemoryPressure() override { - if (!_reportsMemoryPressure) { - return sizeof(GPUTexture); - } - // 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: - case wgpu::TextureFormat::Stencil8: - 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: - case wgpu::TextureFormat::Depth16Unorm: - 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: - case wgpu::TextureFormat::Depth24Plus: - case wgpu::TextureFormat::Depth24PlusStencil8: - case wgpu::TextureFormat::Depth32Float: - 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: - case wgpu::TextureFormat::Depth32FloatStencil8: - 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; - bool _reportsMemoryPressure = true; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUTextureView.h b/packages/skia/cpp/rnwgpu/api/GPUTextureView.h deleted file mode 100644 index 94656b3f06..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUTextureView.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include "descriptors/Unions.h" - -#include "jsi/NativeObject.h" - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUTextureView : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUTextureView"; - - explicit GPUTextureView(wgpu::TextureView instance, std::string label) - : NativeObject(CLASS_NAME), _instance(instance), _label(label) {} - -public: - std::string getBrand() { return CLASS_NAME; } - - std::string getLabel() { return _label; } - void setLabel(const std::string &label) { - _label = label; - _instance.SetLabel(_label.c_str()); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUTextureView::getBrand); - installGetterSetter(runtime, prototype, "label", &GPUTextureView::getLabel, - &GPUTextureView::setLabel); - } - - inline const wgpu::TextureView get() { return _instance; } - -private: - wgpu::TextureView _instance; - std::string _label; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h b/packages/skia/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h deleted file mode 100644 index 71ba5e024b..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "jsi/NativeObject.h" - -#include "GPUError.h" -#include "GPUInternalError.h" -#include "GPUOutOfMemoryError.h" -#include "GPUValidationError.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -using GPUErrorVariant = std::variant, - std::shared_ptr, - std::shared_ptr>; - -class GPUUncapturedErrorEvent : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUUncapturedErrorEvent"; - - explicit GPUUncapturedErrorEvent(GPUErrorVariant error) - : NativeObject(CLASS_NAME), _error(std::move(error)) {} - - GPUErrorVariant getError() { return _error; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "error", - &GPUUncapturedErrorEvent::getError); - } - -private: - GPUErrorVariant _error; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter { - static jsi::Value toJSI(jsi::Runtime &runtime, GPUErrorVariant arg) { - return std::visit( - [&runtime](auto &&error) -> jsi::Value { - using T = std::decay_t; - return JSIConverter::toJSI(runtime, error); - }, - arg); - } - - static GPUErrorVariant fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, - bool outOfBounds) { - throw std::runtime_error("GPUErrorVariant::fromJSI not implemented"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/GPUValidationError.h b/packages/skia/cpp/rnwgpu/api/GPUValidationError.h deleted file mode 100644 index c103ab6606..0000000000 --- a/packages/skia/cpp/rnwgpu/api/GPUValidationError.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUValidationError : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "GPUValidationError"; - - explicit GPUValidationError(std::string message) - : NativeObject(CLASS_NAME), _message(std::move(message)) {} - -public: - std::string getBrand() { return CLASS_NAME; } - std::string getMessage() { return _message; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "__brand", &GPUValidationError::getBrand); - installGetter(runtime, prototype, "message", - &GPUValidationError::getMessage); - } - -private: - std::string _message; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/ImageBitmap.h b/packages/skia/cpp/rnwgpu/api/ImageBitmap.h deleted file mode 100644 index dcaa8ad081..0000000000 --- a/packages/skia/cpp/rnwgpu/api/ImageBitmap.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "jsi/NativeObject.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -// DRAFT — compile-unverified. Minimal ImageBitmap holding decoded, unpremul -// RGBA8 pixels plus its dimensions. Produced by the global createImageBitmap() -// binding (see RNSkManager.cpp). Decoding is done with Skia's own codec, so no -// platform-specific image decoder is required. -// -// FOLLOW-UP: to make an ImageBitmap usable as a copyExternalImageToTexture -// source, uncomment the `source` field + ImageBitmap converter in -// rnwgpu/api/descriptors/GPUImageCopyExternalImage.h and upload `data()` in -// GPUQueue::copyExternalImageToTexture. That GPU wiring is intentionally out of -// scope for this draft. -class ImageBitmap : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "ImageBitmap"; - - ImageBitmap(std::vector data, size_t width, size_t height) - : NativeObject(CLASS_NAME), _data(std::move(data)), _width(width), - _height(height) {} - - size_t getWidth() { return _width; } - - size_t getHeight() { return _height; } - - // Per the spec, close() releases the bitmap's underlying pixels and zeroes - // its dimensions. Idempotent. - void close() { - _data.clear(); - _data.shrink_to_fit(); - _width = 0; - _height = 0; - } - - // Decoded, unpremultiplied RGBA8 pixels (row-major, width*height*4 bytes). - const std::vector &data() const { return _data; } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "width", &ImageBitmap::getWidth); - installGetter(runtime, prototype, "height", &ImageBitmap::getHeight); - installMethod(runtime, prototype, "close", &ImageBitmap::close); - } - - size_t getMemoryPressure() override { return _data.size(); } - -private: - std::vector _data; - size_t _width; - size_t _height; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/NativeBufferUtils.h b/packages/skia/cpp/rnwgpu/api/NativeBufferUtils.h deleted file mode 100644 index e8443b79f9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/NativeBufferUtils.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#if defined(__APPLE__) -#include "AppleNativeBuffer.h" -#elif defined(__ANDROID__) -#include -#endif - -namespace rnwgpu { - -// Import a Skia NativeBuffer pointer (a CVPixelBufferRef on Apple, an -// AHardwareBuffer* on Android, as returned by Skia.NativeBuffer.MakeFromImage / -// MakeTestBuffer) as a wgpu::SharedTextureMemory on `device`. When non-null, -// outWidth/outHeight receive the surface dimensions. Returns a null -// SharedTextureMemory if the import itself fails (the caller decides how to -// report that); throws std::runtime_error for pre-import failures (a buffer -// with no IOSurface, or an unsupported platform). -// -// The platform-specific chained descriptor only needs to outlive the -// ImportSharedTextureMemory call, so it lives entirely within this function. -// Shared by GPUDevice::importSharedTextureMemory and -// GPUExternalTexture::Create. -inline wgpu::SharedTextureMemory importNativeBufferAsSharedTextureMemory( - const wgpu::Device &device, void *bufferPtr, const std::string &label, - uint32_t *outWidth, uint32_t *outHeight) { - wgpu::SharedTextureMemoryDescriptor memDesc{}; - if (!label.empty()) { - memDesc.label = wgpu::StringView(label.c_str(), label.size()); - } - - uint32_t width = 0; - uint32_t height = 0; - wgpu::SharedTextureMemory memory; - -#if defined(__APPLE__) - // Skia's NativeBuffer is a CVPixelBufferRef; extract its backing IOSurface - // (and dimensions) in Objective-C++ since CoreVideo isn't available here. - void *ioSurface = GetIOSurfaceFromNativeBuffer(bufferPtr, &width, &height); - if (ioSurface == nullptr) { - throw std::runtime_error( - "importNativeBufferAsSharedTextureMemory(): native " - "buffer has no IOSurface"); - } - wgpu::SharedTextureMemoryIOSurfaceDescriptor platformDesc{}; - platformDesc.ioSurface = ioSurface; - // Default off: enabling it propagates StorageBinding into properties.usage, - // which then forces memory.createTexture() (no-descriptor form) to validate - // the format against storage capabilities. bgra8unorm (the standard - // CVPixelBuffer format) only supports storage when the device opts into the - // bgra8unorm-storage feature, so unconditionally setting this here breaks the - // common sample-only case. - platformDesc.allowStorageBinding = false; - memDesc.nextInChain = &platformDesc; - memory = device.ImportSharedTextureMemory(&memDesc); -#elif defined(__ANDROID__) - auto *ahb = reinterpret_cast(bufferPtr); - AHardwareBuffer_Desc ahbDesc = {}; - AHardwareBuffer_describe(ahb, &ahbDesc); - width = ahbDesc.width; - height = ahbDesc.height; - wgpu::SharedTextureMemoryAHardwareBufferDescriptor platformDesc{}; - platformDesc.handle = ahb; - memDesc.nextInChain = &platformDesc; - memory = device.ImportSharedTextureMemory(&memDesc); -#else - (void)device; - (void)bufferPtr; - throw std::runtime_error( - "importNativeBufferAsSharedTextureMemory(): unsupported platform"); -#endif - - if (outWidth != nullptr) { - *outWidth = width; - } - if (outHeight != nullptr) { - *outHeight = height; - } - return memory; -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/RNWebGPU.h b/packages/skia/cpp/rnwgpu/api/RNWebGPU.h deleted file mode 100644 index a0d7cc2453..0000000000 --- a/packages/skia/cpp/rnwgpu/api/RNWebGPU.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include - -#include "jsi/NativeObject.h" - -#include "GPU.h" -#include "GPUCanvasContext.h" -#include "rnwgpu/Canvas.h" -#include "rnwgpu/PlatformContext.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class RNWebGPU : public NativeObject { -public: - static constexpr const char *CLASS_NAME = "RNWebGPU"; - - explicit RNWebGPU(std::shared_ptr gpu, - std::shared_ptr platformContext) - : NativeObject(CLASS_NAME), _gpu(gpu), _platformContext(platformContext) { - } - - std::shared_ptr getGPU() { return _gpu; } - - bool getFabric() { return true; } - - std::shared_ptr - MakeWebGPUCanvasContext(int contextId, float width, float height) { - auto ctx = - std::make_shared(_gpu, contextId, width, height); - return ctx; - } - - std::shared_ptr getNativeSurface(int contextId) { - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - auto info = registry.getSurfaceInfo(contextId); - if (info == nullptr) { - return std::make_shared(nullptr, 0, 0); - } - auto nativeInfo = info->getNativeInfo(); - return std::make_shared(nativeInfo.nativeSurface, nativeInfo.width, - nativeInfo.height); - } - - // Retires a canvas context from the JS side (Canvas unmount cleanup). - // Registry entries have two owners, split by whether a native surface is - // attached: - // - A native view currently owns a surface (or one is pending): its own - // teardown (WebGPUMetalView dealloc / WebGPUViewManager.onDropViewInstance) - // removes the entry. Skipping here keeps React StrictMode safe: its - // simulated unmount re-runs JS effects without unmounting native views, - // and removing the entry then would orphan the still-attached surface. - // - No native surface: the JS side is the last owner and removes the entry. - // The check-and-erase runs atomically under the registry lock - // (removeSurfaceInfoIfDetached), serialized against the UI thread's - // find-or-create + attach (SurfaceRegistry::attachSurface), so a concurrent - // attach can never be orphaned by this removal. - void destroyContext(int contextId) { - auto ®istry = rnwgpu::SurfaceRegistry::getInstance(); - registry.removeSurfaceInfoIfDetached(contextId); - } - - static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) { - installGetter(runtime, prototype, "fabric", &RNWebGPU::getFabric); - installGetter(runtime, prototype, "gpu", &RNWebGPU::getGPU); - installMethod(runtime, prototype, "getNativeSurface", - &RNWebGPU::getNativeSurface); - installMethod(runtime, prototype, "destroyContext", - &RNWebGPU::destroyContext); - installMethod(runtime, prototype, "MakeWebGPUCanvasContext", - &RNWebGPU::MakeWebGPUCanvasContext); - } - -private: - std::shared_ptr _gpu; - std::shared_ptr _platformContext; -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/WebGPUConstants.h b/packages/skia/cpp/rnwgpu/api/WebGPUConstants.h deleted file mode 100644 index 7068c88ce7..0000000000 --- a/packages/skia/cpp/rnwgpu/api/WebGPUConstants.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -#include "descriptors/GPUBufferUsage.h" -#include "descriptors/GPUColorWrite.h" -#include "descriptors/GPUMapMode.h" -#include "descriptors/GPUShaderStage.h" -#include "descriptors/GPUTextureUsage.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -// Installs the WebGPU flag constants (GPUBufferUsage, GPUColorWrite, GPUMapMode, -// GPUShaderStage, GPUTextureUsage) as plain JS objects on `runtime`'s global. -// -// The numeric values are derived from the Dawn wgpu::*Usage enums (single source -// of truth in C++), so this is safe to call on ANY runtime: the main JS runtime -// at install time, and any worklet runtime (Reanimated UI, dedicated worklet -// runtimes, Vision Camera frame processors) via the global `installWebGPU()` -// host function. It is idempotent: re-installing overwrites the globals with -// equal values. -inline void installWebGPUConstants(jsi::Runtime &runtime) { - auto global = runtime.global(); - global.setProperty(runtime, "GPUBufferUsage", - GPUBufferUsage::create(runtime)); - global.setProperty(runtime, "GPUColorWrite", GPUColorWrite::create(runtime)); - global.setProperty(runtime, "GPUMapMode", GPUMapMode::create(runtime)); - global.setProperty(runtime, "GPUShaderStage", - GPUShaderStage::create(runtime)); - global.setProperty(runtime, "GPUTextureUsage", - GPUTextureUsage::create(runtime)); -} - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h deleted file mode 100644 index 18df4f42bc..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUBindGroupEntry.h" -#include "rnwgpu/api/GPUBindGroupLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBindGroupDescriptor { - std::shared_ptr layout; // GPUBindGroupLayout - std::vector> - entries; // Iterable - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "layout")) { - auto prop = value.getProperty(runtime, "layout"); - result->layout = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "entries")) { - auto prop = value.getProperty(runtime, "entries"); - result->entries = JSIConverter< - std::vector>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBindGroupDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h deleted file mode 100644 index ed437cfb21..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "GPUBufferBinding.h" -#include "jsi/JSIConverter.h" -#include "rnwgpu/api/GPUExternalTexture.h" -#include "rnwgpu/api/GPUSampler.h" -#include "rnwgpu/api/GPUTextureView.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBindGroupEntry { - double binding; - std::shared_ptr sampler = nullptr; - std::shared_ptr textureView = nullptr; - std::shared_ptr buffer = nullptr; - std::shared_ptr externalTexture = nullptr; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "binding")) { - result->binding = value.getProperty(runtime, "binding").asNumber(); - } - if (value.hasProperty(runtime, "resource")) { - auto prop = value.getProperty(runtime, "resource"); - if (prop.isObject()) { - auto obj = prop.getObject(runtime); - if (obj.hasNativeState(runtime)) { - result->sampler = obj.getNativeState(runtime); - } else if (obj.hasNativeState(runtime)) { - result->textureView = - obj.getNativeState(runtime); - } else if (obj.hasNativeState(runtime)) { - result->externalTexture = - obj.getNativeState(runtime); - } else if (obj.hasNativeState(runtime)) { - auto binding = std::make_shared(); - binding->buffer = obj.getNativeState(runtime); - result->buffer = binding; - } else { - result->buffer = JSIConverter< - std::shared_ptr>::fromJSI(runtime, - prop, - false); - } - } - // result->resource = JSIConverter, std::shared_ptr, - // std::shared_ptr, - // std::shared_ptr>>::fromJSI(runtime, prop, - // false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBindGroupEntry::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h deleted file mode 100644 index 3ad0869521..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUBindGroupLayoutEntry.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBindGroupLayoutDescriptor { - std::vector> - entries; // Iterable - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "entries")) { - auto prop = value.getProperty(runtime, "entries"); - result->entries = JSIConverter>>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBindGroupLayoutDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h deleted file mode 100644 index f86796ee04..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUBufferBindingLayout.h" -#include "GPUExternalTextureBindingLayout.h" -#include "GPUSamplerBindingLayout.h" -#include "GPUStorageTextureBindingLayout.h" -#include "GPUTextureBindingLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBindGroupLayoutEntry { - double binding; // GPUIndex32 - double visibility; // GPUShaderStageFlags - std::optional> - buffer; // GPUBufferBindingLayout - std::optional> - sampler; // GPUSamplerBindingLayout - std::optional> - texture; // GPUTextureBindingLayout - std::optional> - storageTexture; // GPUStorageTextureBindingLayout - std::optional> - externalTexture; // GPUExternalTextureBindingLayout -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "binding")) { - auto prop = value.getProperty(runtime, "binding"); - result->binding = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "visibility")) { - auto prop = value.getProperty(runtime, "visibility"); - result->visibility = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "buffer")) { - auto prop = value.getProperty(runtime, "buffer"); - result->buffer = JSIConverter>>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "sampler")) { - auto prop = value.getProperty(runtime, "sampler"); - result->sampler = JSIConverter>>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "texture")) { - auto prop = value.getProperty(runtime, "texture"); - result->texture = JSIConverter>>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "storageTexture")) { - auto prop = value.getProperty(runtime, "storageTexture"); - result->storageTexture = JSIConverter>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "externalTexture")) { - auto prop = value.getProperty(runtime, "externalTexture"); - result->externalTexture = JSIConverter>>::fromJSI(runtime, - prop, - false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBindGroupLayoutEntry::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h deleted file mode 100644 index 68d49997e0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBlendComponent { - std::optional operation; // GPUBlendOperation - std::optional srcFactor; // GPUBlendFactor - std::optional dstFactor; // GPUBlendFactor -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "operation")) { - auto prop = value.getProperty(runtime, "operation"); - result->operation = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "srcFactor")) { - auto prop = value.getProperty(runtime, "srcFactor"); - result->srcFactor = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "dstFactor")) { - auto prop = value.getProperty(runtime, "dstFactor"); - result->dstFactor = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBlendComponent::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendState.h deleted file mode 100644 index d4806f1a66..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBlendState.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUBlendComponent.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBlendState { - std::shared_ptr color; // GPUBlendComponent - std::shared_ptr alpha; // GPUBlendComponent -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "color")) { - auto prop = value.getProperty(runtime, "color"); - result->color = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "alpha")) { - auto prop = value.getProperty(runtime, "alpha"); - result->alpha = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBlendState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h deleted file mode 100644 index f451de3625..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUBuffer.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBufferBinding { - std::shared_ptr buffer; // GPUBuffer - std::optional offset; // GPUSize64 - std::optional size; // GPUSize64 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "buffer")) { - auto prop = value.getProperty(runtime, "buffer"); - result->buffer = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "offset")) { - auto prop = value.getProperty(runtime, "offset"); - result->offset = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "size")) { - auto prop = value.getProperty(runtime, "size"); - result->size = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBufferBinding::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h deleted file mode 100644 index 2a961fd5f5..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBufferBindingLayout { - std::optional type; // GPUBufferBindingType - std::optional hasDynamicOffset; // boolean - std::optional minBindingSize; // GPUSize64 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "type")) { - auto prop = value.getProperty(runtime, "type"); - result->type = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "hasDynamicOffset")) { - auto prop = value.getProperty(runtime, "hasDynamicOffset"); - result->hasDynamicOffset = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "minBindingSize")) { - auto prop = value.getProperty(runtime, "minBindingSize"); - result->minBindingSize = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBufferBindingLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h deleted file mode 100644 index e1e1b544fb..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUBufferDescriptor { - double size; // GPUSize64 - double usage; // GPUBufferUsageFlags - std::optional mappedAtCreation; // boolean - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "size")) { - auto prop = value.getProperty(runtime, "size"); - result->size = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "usage")) { - auto prop = value.getProperty(runtime, "usage"); - result->usage = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "mappedAtCreation")) { - auto prop = value.getProperty(runtime, "mappedAtCreation"); - result->mappedAtCreation = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUBufferDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h deleted file mode 100644 index 24f18e5da3..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUBufferUsage { -public: - static jsi::Object create(jsi::Runtime &runtime) { - jsi::Object obj(runtime); - obj.setProperty(runtime, "MAP_READ", - static_cast(wgpu::BufferUsage::MapRead)); - obj.setProperty(runtime, "MAP_WRITE", - static_cast(wgpu::BufferUsage::MapWrite)); - obj.setProperty(runtime, "COPY_SRC", - static_cast(wgpu::BufferUsage::CopySrc)); - obj.setProperty(runtime, "COPY_DST", - static_cast(wgpu::BufferUsage::CopyDst)); - obj.setProperty(runtime, "INDEX", - static_cast(wgpu::BufferUsage::Index)); - obj.setProperty(runtime, "VERTEX", - static_cast(wgpu::BufferUsage::Vertex)); - obj.setProperty(runtime, "UNIFORM", - static_cast(wgpu::BufferUsage::Uniform)); - obj.setProperty(runtime, "STORAGE", - static_cast(wgpu::BufferUsage::Storage)); - obj.setProperty(runtime, "INDIRECT", - static_cast(wgpu::BufferUsage::Indirect)); - obj.setProperty(runtime, "QUERY_RESOLVE", - static_cast(wgpu::BufferUsage::QueryResolve)); - return obj; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h deleted file mode 100644 index 6b6ecb5449..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUDevice.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUCanvasConfiguration { - std::shared_ptr device; // GPUDevice - wgpu::TextureFormat format; // GPUTextureFormat - std::optional usage; // GPUTextureUsageFlags - std::optional> - viewFormats; // Iterable - wgpu::CompositeAlphaMode alphaMode = wgpu::CompositeAlphaMode::Opaque; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "device")) { - auto prop = value.getProperty(runtime, "device"); - result->device = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "usage")) { - auto prop = value.getProperty(runtime, "usage"); - result->usage = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "viewFormats")) { - auto prop = value.getProperty(runtime, "viewFormats"); - result->viewFormats = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "alphaMode")) { - auto prop = value.getProperty(runtime, "alphaMode") - .asString(runtime) - .utf8(runtime); - if (prop == "premultiplied") { - result->alphaMode = wgpu::CompositeAlphaMode::Premultiplied; - } - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUCanvasConfiguration::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUColor.h deleted file mode 100644 index 5214ae9268..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColor.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUColor { - double r; // number - double g; // number - double b; // number - double a; // number -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.isArray(runtime)) { - auto array = value.getArray(runtime); - if (array.size(runtime) >= 4) { - result->r = array.getValueAtIndex(runtime, 0).getNumber(); - result->g = array.getValueAtIndex(runtime, 1).getNumber(); - result->b = array.getValueAtIndex(runtime, 2).getNumber(); - result->a = array.getValueAtIndex(runtime, 3).getNumber(); - } - } else { - if (value.hasProperty(runtime, "r")) { - auto prop = value.getProperty(runtime, "r"); - result->r = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "g")) { - auto prop = value.getProperty(runtime, "g"); - result->g = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "b")) { - auto prop = value.getProperty(runtime, "b"); - result->b = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "a")) { - auto prop = value.getProperty(runtime, "a"); - result->a = JSIConverter::fromJSI(runtime, prop, false); - } - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUColor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h deleted file mode 100644 index f5c84409a1..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUBlendState.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUColorTargetState { - wgpu::TextureFormat format; // GPUTextureFormat - std::optional> blend; // GPUBlendState - std::optional writeMask; // GPUColorWriteFlags -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "blend")) { - auto prop = value.getProperty(runtime, "blend"); - result->blend = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "writeMask")) { - auto prop = value.getProperty(runtime, "writeMask"); - result->writeMask = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUColorTargetState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorWrite.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorWrite.h deleted file mode 100644 index 6804fb40f5..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUColorWrite.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUColorWrite { -public: - static jsi::Object create(jsi::Runtime &runtime) { - jsi::Object obj(runtime); - obj.setProperty(runtime, "RED", - static_cast(wgpu::ColorWriteMask::Red)); - obj.setProperty(runtime, "GREEN", - static_cast(wgpu::ColorWriteMask::Green)); - obj.setProperty(runtime, "BLUE", - static_cast(wgpu::ColorWriteMask::Blue)); - obj.setProperty(runtime, "ALPHA", - static_cast(wgpu::ColorWriteMask::Alpha)); - obj.setProperty(runtime, "ALL", - static_cast(wgpu::ColorWriteMask::All)); - return obj; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandBufferDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandBufferDescriptor.h deleted file mode 100644 index 75cd9bd2ef..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandBufferDescriptor.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUCommandBufferDescriptor { - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUCommandBufferDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandEncoderDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandEncoderDescriptor.h deleted file mode 100644 index 0dfebc3448..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUCommandEncoderDescriptor.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUCommandEncoderDescriptor { - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUCommandEncoderDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h deleted file mode 100644 index 828d4ed4b8..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUComputePassTimestampWrites.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUComputePassDescriptor { - std::optional> - timestampWrites; // GPUComputePassTimestampWrites - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "timestampWrites")) { - auto prop = value.getProperty(runtime, "timestampWrites"); - result->timestampWrites = JSIConverter>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUComputePassDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h deleted file mode 100644 index 3e3298007f..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUQuerySet.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUComputePassTimestampWrites { - std::shared_ptr querySet; // GPUQuerySet - std::optional beginningOfPassWriteIndex; // GPUSize32 - std::optional endOfPassWriteIndex; // GPUSize32 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "querySet")) { - auto prop = value.getProperty(runtime, "querySet"); - result->querySet = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "beginningOfPassWriteIndex")) { - auto prop = value.getProperty(runtime, "beginningOfPassWriteIndex"); - result->beginningOfPassWriteIndex = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "endOfPassWriteIndex")) { - auto prop = value.getProperty(runtime, "endOfPassWriteIndex"); - result->endOfPassWriteIndex = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUComputePassTimestampWrites::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h deleted file mode 100644 index fda9329995..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUProgrammableStage.h" -#include "rnwgpu/api/GPUPipelineLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUComputePipelineDescriptor { - std::shared_ptr compute; // GPUProgrammableStage - std::variant> - layout; // | GPUPipelineLayout | GPUAutoLayoutMode - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "compute")) { - auto prop = value.getProperty(runtime, "compute"); - result->compute = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "layout")) { - auto prop = value.getProperty(runtime, "layout"); - if (prop.isNull() || prop.isString()) { - result->layout = nullptr; - } else { - result->layout = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUComputePipelineDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h deleted file mode 100644 index d92f913442..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -// Non-standard, Dawn-only. Mirrors wgpu::DawnTogglesDescriptor field-for-field -// so the mapping to the native chained struct is 1:1. Chained onto the -// wgpu::DeviceDescriptor in GPUAdapter::requestDevice. -struct GPUDawnTogglesDescriptor { - std::optional> enabledToggles; // Iterable - std::optional> disabledToggles; // Iterable -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "enabledToggles")) { - auto prop = value.getProperty(runtime, "enabledToggles"); - result->enabledToggles = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "disabledToggles")) { - auto prop = value.getProperty(runtime, "disabledToggles"); - result->disabledToggles = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - } - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUDawnTogglesDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h deleted file mode 100644 index 116dd7af22..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUStencilFaceState.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUDepthStencilState { - wgpu::TextureFormat format; // GPUTextureFormat - std::optional depthWriteEnabled; // boolean - std::optional depthCompare; // GPUCompareFunction - std::optional> - stencilFront; // GPUStencilFaceState - std::optional> - stencilBack; // GPUStencilFaceState - std::optional stencilReadMask; // GPUStencilValue - std::optional stencilWriteMask; // GPUStencilValue - std::optional depthBias; // GPUDepthBias - std::optional depthBiasSlopeScale; // number - std::optional depthBiasClamp; // number -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthWriteEnabled")) { - auto prop = value.getProperty(runtime, "depthWriteEnabled"); - result->depthWriteEnabled = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthCompare")) { - auto prop = value.getProperty(runtime, "depthCompare"); - result->depthCompare = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilFront")) { - auto prop = value.getProperty(runtime, "stencilFront"); - result->stencilFront = - JSIConverter>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilBack")) { - auto prop = value.getProperty(runtime, "stencilBack"); - result->stencilBack = - JSIConverter>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilReadMask")) { - auto prop = value.getProperty(runtime, "stencilReadMask"); - result->stencilReadMask = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilWriteMask")) { - auto prop = value.getProperty(runtime, "stencilWriteMask"); - result->stencilWriteMask = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthBias")) { - auto prop = value.getProperty(runtime, "depthBias"); - result->depthBias = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthBiasSlopeScale")) { - auto prop = value.getProperty(runtime, "depthBiasSlopeScale"); - result->depthBiasSlopeScale = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthBiasClamp")) { - auto prop = value.getProperty(runtime, "depthBiasClamp"); - result->depthBiasClamp = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUDepthStencilState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h deleted file mode 100644 index 1c747103d2..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUDawnTogglesDescriptor.h" -#include "GPUQueueDescriptor.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUDeviceDescriptor { - std::optional> - requiredFeatures; // Iterable - std::optional> - requiredLimits; // Record< string, GPUSize64 > - std::optional> - defaultQueue; // GPUQueueDescriptor - std::optional label; // string - // Non-standard Dawn-only device toggles, chained onto the wgpu::Device - // descriptor in GPUAdapter::requestDevice. - std::optional> dawnToggles; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -// We add this extra convertor because we found so library that are sending -// invalid feature elements -template <> struct JSIConverter> { - - static std::vector - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - jsi::Array array = arg.asObject(runtime).asArray(runtime); - size_t length = array.size(runtime); - - std::vector vector; - vector.reserve(length); - for (size_t i = 0; i < length; ++i) { - jsi::Value elementValue = array.getValueAtIndex(runtime, i); - if (elementValue.isString()) { - vector.emplace_back(JSIConverter::fromJSI( - runtime, elementValue, outOfBounds)); - } - } - return vector; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error( - "Invalid JSIConverter>::toJSI()"); - } -}; - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "requiredFeatures")) { - auto prop = value.getProperty(runtime, "requiredFeatures"); - result->requiredFeatures = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "requiredLimits")) { - auto prop = value.getProperty(runtime, "requiredLimits"); - result->requiredLimits = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "defaultQueue")) { - auto prop = value.getProperty(runtime, "defaultQueue"); - result->defaultQueue = - JSIConverter>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "dawnToggles")) { - auto prop = value.getProperty(runtime, "dawnToggles"); - result->dawnToggles = JSIConverter>>::fromJSI(runtime, prop, - false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUDeviceDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h deleted file mode 100644 index 752894d0e5..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUExternalTextureBindingLayout {}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error( - "Invalid GPUExternalTextureBindingLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h deleted file mode 100644 index d6c3a6fa41..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -// Mirror of GPUExternalTextureDescriptor from the WebGPU spec, adapted to -// Skia's binding. Skia has no VideoFrame; instead `source` is a native buffer -// pointer (the BigInt returned by Skia.NativeBuffer.MakeFromImage): a -// CVPixelBufferRef on Apple, an AHardwareBuffer* on Android. The pointer's -// lifetime is owned by the caller (Skia.NativeBuffer.Release); the imported -// texture must not outlive it. -// -// We don't expose colorSpace yet; the C++ side picks dst-sRGB and identity -// gamut, the right default for "render this BGRA frame to an sRGB framebuffer". -// -// `rotation` / `mirrored` are a non-spec extension baked into Dawn's sampling -// transform. `rotation` is in degrees and must be one of 0 / 90 / 180 / 270. -struct GPUExternalTextureDescriptor { - // native buffer pointer (CVPixelBufferRef / AHardwareBuffer*) - uint64_t source = 0; - std::optional label; - std::optional rotation; - std::optional mirrored; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_shared(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "source")) { - auto prop = value.getProperty(runtime, "source"); - // The native buffer pointer arrives as a BigInt (uintptr_t value). It - // must be a BigInt: a JS number can't represent a 64-bit pointer - // without truncation, so we reject it rather than corrupt the address. - if (prop.isBigInt()) { - result->source = prop.asBigInt(runtime).asUint64(runtime); - } else if (!prop.isUndefined() && !prop.isNull()) { - throw jsi::JSError( - runtime, "GPUExternalTextureDescriptor.source must be a " - "NativeBuffer (BigInt) from " - "Skia.NativeBuffer.MakeFromImage / MakeTestBuffer"); - } - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - if (!prop.isUndefined()) { - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - if (value.hasProperty(runtime, "rotation")) { - auto prop = value.getProperty(runtime, "rotation"); - if (prop.isNumber()) { - result->rotation = prop.asNumber(); - } - } - if (value.hasProperty(runtime, "mirrored")) { - auto prop = value.getProperty(runtime, "mirrored"); - if (prop.isBool()) { - result->mirrored = prop.getBool(); - } - } - } - return result; - } - static jsi::Value - toJSI(jsi::Runtime & /*runtime*/, - std::shared_ptr /*arg*/) { - throw std::runtime_error("Invalid GPUExternalTextureDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUFragmentState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUFragmentState.h deleted file mode 100644 index b5b37d666a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUFragmentState.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUColorTargetState.h" -#include "rnwgpu/api/GPUShaderModule.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUFragmentState { - std::vector< - std::variant>> - targets; // Iterable - std::shared_ptr module; // GPUShaderModule - std::optional entryPoint; // string - std::optional> - constants; // Record< string, GPUPipelineConstantValue > -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "targets")) { - auto prop = value.getProperty(runtime, "targets"); - result->targets = JSIConverter>>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "module")) { - auto prop = value.getProperty(runtime, "module"); - result->module = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "entryPoint")) { - auto prop = value.getProperty(runtime, "entryPoint"); - result->entryPoint = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "constants")) { - auto prop = value.getProperty(runtime, "constants"); - result->constants = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUFragmentState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h deleted file mode 100644 index beb5346ac0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUBuffer.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUImageCopyBuffer { - std::shared_ptr buffer; // GPUBuffer - std::optional offset; // GPUSize64 - std::optional bytesPerRow; // GPUSize32 - std::optional rowsPerImage; // GPUSize32 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "buffer")) { - auto prop = value.getProperty(runtime, "buffer"); - result->buffer = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "offset")) { - auto prop = value.getProperty(runtime, "offset"); - result->offset = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "bytesPerRow")) { - auto prop = value.getProperty(runtime, "bytesPerRow"); - result->bytesPerRow = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "rowsPerImage")) { - auto prop = value.getProperty(runtime, "rowsPerImage"); - result->rowsPerImage = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUImageCopyBuffer::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h deleted file mode 100644 index fa56dd2b2e..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" -#include "rnwgpu/api/Convertors.h" - -#include "rnwgpu/api/GPUOrigin2D.h" -#include "rnwgpu/api/ImageBitmap.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUImageCopyExternalImage { - std::shared_ptr source; // GPUImageCopyExternalImageSource - std::optional> origin; // GPUOrigin2DStrict - std::optional flipY; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto obj = arg.getObject(runtime); - if (obj.hasProperty(runtime, "source")) { - auto prop = obj.getProperty(runtime, "source"); - result->source = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (obj.hasProperty(runtime, "origin")) { - auto prop = obj.getProperty(runtime, "origin"); - result->origin = JSIConverter>::fromJSI( - runtime, prop, false); - } - - if (obj.hasProperty(runtime, "flipY")) { - auto prop = obj.getProperty(runtime, "flipY"); - result->flipY = JSIConverter::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUImageCopyExternalImage::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h deleted file mode 100644 index 17afe808b4..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUOrigin3D.h" -#include "rnwgpu/api/GPUTexture.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUImageCopyTexture { - std::shared_ptr texture; // GPUTexture - std::optional mipLevel; // GPUIntegerCoordinate - std::optional> origin; // GPUOrigin3D - std::optional aspect; // GPUTextureAspect -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "texture")) { - auto prop = value.getProperty(runtime, "texture"); - result->texture = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "mipLevel")) { - auto prop = value.getProperty(runtime, "mipLevel"); - result->mipLevel = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "origin")) { - auto prop = value.getProperty(runtime, "origin"); - result->origin = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "aspect")) { - auto prop = value.getProperty(runtime, "aspect"); - result->aspect = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUImageCopyTexture::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h deleted file mode 100644 index bf52d4cfbe..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/External.h" -#include "rnwgpu/api/GPUOrigin3D.h" -#include "rnwgpu/api/GPUTexture.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUImageCopyTextureTagged { - std::optional colorSpace; // PredefinedColorSpace - std::optional premultipliedAlpha; // boolean - std::shared_ptr texture; // GPUTexture - std::optional mipLevel; // GPUIntegerCoordinate - std::optional> origin; // GPUOrigin3D - std::optional aspect; // GPUTextureAspect -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "colorSpace")) { - auto prop = value.getProperty(runtime, "colorSpace"); - result->colorSpace = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "premultipliedAlpha")) { - auto prop = value.getProperty(runtime, "premultipliedAlpha"); - result->premultipliedAlpha = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "texture")) { - auto prop = value.getProperty(runtime, "texture"); - result->texture = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "mipLevel")) { - auto prop = value.getProperty(runtime, "mipLevel"); - result->mipLevel = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "origin")) { - auto prop = value.getProperty(runtime, "origin"); - result->origin = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "aspect")) { - auto prop = value.getProperty(runtime, "aspect"); - result->aspect = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUImageCopyTextureTagged::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h deleted file mode 100644 index e59f4a674b..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUImageDataLayout { - std::optional offset; // GPUSize64 - std::optional bytesPerRow; // GPUSize32 - std::optional rowsPerImage; // GPUSize32 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "offset")) { - auto prop = value.getProperty(runtime, "offset"); - result->offset = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "bytesPerRow")) { - auto prop = value.getProperty(runtime, "bytesPerRow"); - result->bytesPerRow = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "rowsPerImage")) { - auto prop = value.getProperty(runtime, "rowsPerImage"); - result->rowsPerImage = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUImageDataLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUMapMode.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUMapMode.h deleted file mode 100644 index 2cd0c0ccac..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUMapMode.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUMapMode { -public: - static jsi::Object create(jsi::Runtime &runtime) { - jsi::Object obj(runtime); - obj.setProperty(runtime, "READ", static_cast(wgpu::MapMode::Read)); - obj.setProperty(runtime, "WRITE", - static_cast(wgpu::MapMode::Write)); - return obj; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h deleted file mode 100644 index 4c8649b330..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUMultisampleState { - std::optional count; // GPUSize32 - std::optional mask; // GPUSampleMask - std::optional alphaToCoverageEnabled; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "count")) { - auto prop = value.getProperty(runtime, "count"); - result->count = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "mask")) { - auto prop = value.getProperty(runtime, "mask"); - result->mask = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "alphaToCoverageEnabled")) { - auto prop = value.getProperty(runtime, "alphaToCoverageEnabled"); - result->alphaToCoverageEnabled = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUMultisampleState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h deleted file mode 100644 index 9b32c521da..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUBindGroupLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUPipelineLayoutDescriptor { - std::vector> - bindGroupLayouts; // Iterable - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "bindGroupLayouts")) { - auto prop = value.getProperty(runtime, "bindGroupLayouts"); - result->bindGroupLayouts = JSIConverter< - std::vector>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUPipelineLayoutDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h deleted file mode 100644 index 0f921a8ce2..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUPrimitiveState { - std::optional topology; // GPUPrimitiveTopology - std::optional stripIndexFormat; // GPUIndexFormat - std::optional frontFace; // GPUFrontFace - std::optional cullMode; // GPUCullMode - std::optional unclippedDepth; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "topology")) { - auto prop = value.getProperty(runtime, "topology"); - result->topology = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "stripIndexFormat")) { - auto prop = value.getProperty(runtime, "stripIndexFormat"); - result->stripIndexFormat = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "frontFace")) { - auto prop = value.getProperty(runtime, "frontFace"); - result->frontFace = - JSIConverter>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "cullMode")) { - auto prop = value.getProperty(runtime, "cullMode"); - result->cullMode = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "unclippedDepth")) { - auto prop = value.getProperty(runtime, "unclippedDepth"); - result->unclippedDepth = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUPrimitiveState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h deleted file mode 100644 index 37fcc2ab2e..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUShaderModule.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUProgrammableStage { - std::shared_ptr module; // GPUShaderModule - std::optional entryPoint; // string - std::optional> - constants; // Record< string, GPUPipelineConstantValue > -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "module")) { - auto prop = value.getProperty(runtime, "module"); - result->module = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "entryPoint")) { - auto prop = value.getProperty(runtime, "entryPoint"); - result->entryPoint = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "constants")) { - auto prop = value.getProperty(runtime, "constants"); - result->constants = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUProgrammableStage::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h deleted file mode 100644 index 059bcbb4f0..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUQuerySetDescriptor { - wgpu::QueryType type; // GPUQueryType - double count; // GPUSize32 - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "type")) { - auto prop = value.getProperty(runtime, "type"); - result->type = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "count")) { - auto prop = value.getProperty(runtime, "count"); - result->count = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUQuerySetDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUQueueDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUQueueDescriptor.h deleted file mode 100644 index fd01f26644..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUQueueDescriptor.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUQueueDescriptor { - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUQueueDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleDescriptor.h deleted file mode 100644 index 24d542e07a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleDescriptor.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderBundleDescriptor { - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURenderBundleDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h deleted file mode 100644 index 4b47a0f25e..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderBundleEncoderDescriptor { - std::optional depthReadOnly; // boolean - std::optional stencilReadOnly; // boolean - std::vector> - colorFormats; // Iterable - std::optional depthStencilFormat; // GPUTextureFormat - std::optional sampleCount; // GPUSize32 - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "depthReadOnly")) { - auto prop = value.getProperty(runtime, "depthReadOnly"); - result->depthReadOnly = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilReadOnly")) { - auto prop = value.getProperty(runtime, "stencilReadOnly"); - result->stencilReadOnly = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "colorFormats")) { - auto prop = value.getProperty(runtime, "colorFormats"); - result->colorFormats = JSIConverter< - std::vector>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthStencilFormat")) { - auto prop = value.getProperty(runtime, "depthStencilFormat"); - result->depthStencilFormat = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "sampleCount")) { - auto prop = value.getProperty(runtime, "sampleCount"); - result->sampleCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error( - "Invalid GPURenderBundleEncoderDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h deleted file mode 100644 index 639ab41571..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUColor.h" -#include "rnwgpu/api/GPUTextureView.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderPassColorAttachment { - std::shared_ptr view; // GPUTextureView - std::optional depthSlice; // GPUIntegerCoordinate - std::optional> - resolveTarget; // GPUTextureView - std::optional> clearValue; // GPUColor - wgpu::LoadOp loadOp; // GPULoadOp - wgpu::StoreOp storeOp; // GPUStoreOp -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "view")) { - auto prop = value.getProperty(runtime, "view"); - result->view = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "depthSlice")) { - auto prop = value.getProperty(runtime, "depthSlice"); - result->depthSlice = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "resolveTarget")) { - auto prop = value.getProperty(runtime, "resolveTarget"); - result->resolveTarget = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "clearValue")) { - auto prop = value.getProperty(runtime, "clearValue"); - result->clearValue = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "loadOp")) { - auto prop = value.getProperty(runtime, "loadOp"); - result->loadOp = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "storeOp")) { - auto prop = value.getProperty(runtime, "storeOp"); - result->storeOp = - JSIConverter::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURenderPassColorAttachment::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h deleted file mode 100644 index 9e7aab37bc..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUTextureView.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderPassDepthStencilAttachment { - std::shared_ptr view; // GPUTextureView - std::optional depthClearValue; // number - std::optional depthLoadOp; // GPULoadOp - std::optional depthStoreOp; // GPUStoreOp - std::optional depthReadOnly; // boolean - std::optional stencilClearValue; // GPUStencilValue - std::optional stencilLoadOp; // GPULoadOp - std::optional stencilStoreOp; // GPUStoreOp - std::optional stencilReadOnly; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter< - std::shared_ptr> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = - std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "view")) { - auto prop = value.getProperty(runtime, "view"); - result->view = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "depthClearValue")) { - auto prop = value.getProperty(runtime, "depthClearValue"); - result->depthClearValue = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthLoadOp")) { - auto prop = value.getProperty(runtime, "depthLoadOp"); - result->depthLoadOp = - JSIConverter>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "depthStoreOp")) { - auto prop = value.getProperty(runtime, "depthStoreOp"); - result->depthStoreOp = - JSIConverter>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "depthReadOnly")) { - auto prop = value.getProperty(runtime, "depthReadOnly"); - result->depthReadOnly = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilClearValue")) { - auto prop = value.getProperty(runtime, "stencilClearValue"); - result->stencilClearValue = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stencilLoadOp")) { - auto prop = value.getProperty(runtime, "stencilLoadOp"); - result->stencilLoadOp = - JSIConverter>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "stencilStoreOp")) { - auto prop = value.getProperty(runtime, "stencilStoreOp"); - result->stencilStoreOp = - JSIConverter>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "stencilReadOnly")) { - auto prop = value.getProperty(runtime, "stencilReadOnly"); - result->stencilReadOnly = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error( - "Invalid GPURenderPassDepthStencilAttachment::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h deleted file mode 100644 index 2b6ed03247..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPURenderPassColorAttachment.h" -#include "GPURenderPassDepthStencilAttachment.h" -#include "GPURenderPassTimestampWrites.h" -#include "rnwgpu/api/GPUQuerySet.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderPassDescriptor { - std::vector>> - colorAttachments; // Iterable - std::optional> - depthStencilAttachment; // GPURenderPassDepthStencilAttachment - std::optional> occlusionQuerySet; // GPUQuerySet - std::optional> - timestampWrites; // GPURenderPassTimestampWrites - std::optional maxDrawCount; // GPUSize64 - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "colorAttachments")) { - auto prop = value.getProperty(runtime, "colorAttachments"); - result->colorAttachments = JSIConverter>>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "depthStencilAttachment")) { - auto prop = value.getProperty(runtime, "depthStencilAttachment"); - result->depthStencilAttachment = - JSIConverter>>::fromJSI(runtime, prop, - false); - } - if (value.hasProperty(runtime, "occlusionQuerySet")) { - auto prop = value.getProperty(runtime, "occlusionQuerySet"); - result->occlusionQuerySet = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "timestampWrites")) { - auto prop = value.getProperty(runtime, "timestampWrites"); - result->timestampWrites = JSIConverter>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "maxDrawCount")) { - auto prop = value.getProperty(runtime, "maxDrawCount"); - result->maxDrawCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURenderPassDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h deleted file mode 100644 index bd5ada293a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUQuerySet.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderPassTimestampWrites { - std::shared_ptr querySet; // GPUQuerySet - std::optional beginningOfPassWriteIndex; // GPUSize32 - std::optional endOfPassWriteIndex; // GPUSize32 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "querySet")) { - auto prop = value.getProperty(runtime, "querySet"); - result->querySet = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "beginningOfPassWriteIndex")) { - auto prop = value.getProperty(runtime, "beginningOfPassWriteIndex"); - result->beginningOfPassWriteIndex = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "endOfPassWriteIndex")) { - auto prop = value.getProperty(runtime, "endOfPassWriteIndex"); - result->endOfPassWriteIndex = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURenderPassTimestampWrites::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h deleted file mode 100644 index b73426eef9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUDepthStencilState.h" -#include "GPUFragmentState.h" -#include "GPUMultisampleState.h" -#include "GPUPrimitiveState.h" -#include "GPUVertexState.h" -#include "rnwgpu/api/GPUPipelineLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURenderPipelineDescriptor { - std::shared_ptr vertex; // GPUVertexState - std::optional> - primitive; // GPUPrimitiveState - std::optional> - depthStencil; // GPUDepthStencilState - std::optional> - multisample; // GPUMultisampleState - std::optional> fragment; // GPUFragmentState - std::variant> - layout; // | GPUPipelineLayout | GPUAutoLayoutMode - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "vertex")) { - auto prop = value.getProperty(runtime, "vertex"); - result->vertex = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "primitive")) { - auto prop = value.getProperty(runtime, "primitive"); - result->primitive = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "depthStencil")) { - auto prop = value.getProperty(runtime, "depthStencil"); - result->depthStencil = - JSIConverter>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "multisample")) { - auto prop = value.getProperty(runtime, "multisample"); - result->multisample = - JSIConverter>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "fragment")) { - auto prop = value.getProperty(runtime, "fragment"); - result->fragment = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "layout")) { - auto prop = value.getProperty(runtime, "layout"); - if (prop.isNull() || prop.isString()) { - result->layout = nullptr; - } else { - result->layout = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURenderPipelineDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h deleted file mode 100644 index 2e11a27815..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPURequestAdapterOptions { - std::optional powerPreference; // GPUPowerPreference - std::optional forceFallbackAdapter; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "powerPreference")) { - auto prop = value.getProperty(runtime, "powerPreference"); - result->powerPreference = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "forceFallbackAdapter")) { - auto prop = value.getProperty(runtime, "forceFallbackAdapter"); - result->forceFallbackAdapter = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPURequestAdapterOptions::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h deleted file mode 100644 index 934a850812..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUSamplerBindingLayout { - std::optional type; // GPUSamplerBindingType -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "type")) { - auto prop = value.getProperty(runtime, "type"); - result->type = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUSamplerBindingLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h deleted file mode 100644 index f1428f032e..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUSamplerDescriptor { - std::optional addressModeU; // GPUAddressMode - std::optional addressModeV; // GPUAddressMode - std::optional addressModeW; // GPUAddressMode - std::optional magFilter; // GPUFilterMode - std::optional minFilter; // GPUFilterMode - std::optional mipmapFilter; // GPUMipmapFilterMode - std::optional lodMinClamp; // number - std::optional lodMaxClamp; // number - std::optional compare; // GPUCompareFunction - std::optional maxAnisotropy; // number - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "addressModeU")) { - auto prop = value.getProperty(runtime, "addressModeU"); - result->addressModeU = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "addressModeV")) { - auto prop = value.getProperty(runtime, "addressModeV"); - result->addressModeV = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "addressModeW")) { - auto prop = value.getProperty(runtime, "addressModeW"); - result->addressModeW = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "magFilter")) { - auto prop = value.getProperty(runtime, "magFilter"); - result->magFilter = - JSIConverter>::fromJSI(runtime, - prop, false); - } - if (value.hasProperty(runtime, "minFilter")) { - auto prop = value.getProperty(runtime, "minFilter"); - result->minFilter = - JSIConverter>::fromJSI(runtime, - prop, false); - } - if (value.hasProperty(runtime, "mipmapFilter")) { - auto prop = value.getProperty(runtime, "mipmapFilter"); - result->mipmapFilter = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "lodMinClamp")) { - auto prop = value.getProperty(runtime, "lodMinClamp"); - result->lodMinClamp = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "lodMaxClamp")) { - auto prop = value.getProperty(runtime, "lodMaxClamp"); - result->lodMaxClamp = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "compare")) { - auto prop = value.getProperty(runtime, "compare"); - result->compare = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "maxAnisotropy")) { - auto prop = value.getProperty(runtime, "maxAnisotropy"); - result->maxAnisotropy = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUSamplerDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h deleted file mode 100644 index 47fff28e5c..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUPipelineLayout.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUShaderModuleCompilationHint { - std::string entryPoint; // string - std::optional< - std::variant>> - layout; // | GPUPipelineLayout | GPUAutoLayoutMode -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "entryPoint")) { - auto prop = value.getProperty(runtime, "entryPoint"); - result->entryPoint = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "layout")) { - auto prop = value.getProperty(runtime, "layout"); - if (prop.isNull() || prop.isString()) { - result->layout = nullptr; - } else { - result->layout = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUShaderModuleCompilationHint::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h deleted file mode 100644 index 32b823adc6..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUShaderModuleCompilationHint.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUShaderModuleDescriptor { - std::string code; // string - std::optional>> - compilationHints; // Array - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "code")) { - auto prop = value.getProperty(runtime, "code"); - result->code = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "compilationHints")) { - auto prop = value.getProperty(runtime, "compilationHints"); - result->compilationHints = JSIConverter>>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUShaderModuleDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderStage.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderStage.h deleted file mode 100644 index c9b69645ca..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUShaderStage.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUShaderStage { -public: - static jsi::Object create(jsi::Runtime &runtime) { - jsi::Object obj(runtime); - obj.setProperty(runtime, "VERTEX", - static_cast(wgpu::ShaderStage::Vertex)); - obj.setProperty(runtime, "FRAGMENT", - static_cast(wgpu::ShaderStage::Fragment)); - obj.setProperty(runtime, "COMPUTE", - static_cast(wgpu::ShaderStage::Compute)); - return obj; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h deleted file mode 100644 index 47efb8893e..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -// Descriptor for GPUDevice.importSharedFence. `handle` is the native handle -// (an id pointer on Apple, an OS file descriptor on Android), -// passed from JS as a BigInt. -struct GPUSharedFenceDescriptor { - std::string type; - void *handle = nullptr; - std::optional label; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "type")) { - result->type = - value.getProperty(runtime, "type").asString(runtime).utf8(runtime); - } - if (value.hasProperty(runtime, "handle")) { - auto prop = value.getProperty(runtime, "handle"); - result->handle = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - return result; - } - static jsi::Value - toJSI(jsi::Runtime & /*runtime*/, - std::shared_ptr /*arg*/) { - throw std::runtime_error("Invalid GPUSharedFenceDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h deleted file mode 100644 index b08741dfff..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUSharedFence.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -// A fence and the timeline value to wait for / signal at. -struct GPUSharedFenceState { - std::shared_ptr fence; - uint64_t signaledValue = 0; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "fence")) { - auto prop = value.getProperty(runtime, "fence"); - result->fence = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "signaledValue")) { - auto prop = value.getProperty(runtime, "signaledValue"); - result->signaledValue = - JSIConverter::fromJSI(runtime, prop, false); - } - } - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUSharedFenceState::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h deleted file mode 100644 index d86e679b33..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -// Descriptor for GPUDevice.importSharedTextureMemory. -// -// `handle` is a native buffer pointer as a uintptr_t (passed as a BigInt from -// JS), i.e. the value returned by Skia.NativeBuffer.MakeFromImage: -// - Apple platforms: CVPixelBufferRef (its backing IOSurface is imported) -// - Android: AHardwareBuffer* -// -// Lifetime: the caller is responsible for keeping the underlying object alive -// (via Skia.NativeBuffer.Release) for as long as this shared memory is in use. -struct GPUSharedTextureMemoryDescriptor { - uint64_t handle = 0; - std::optional label; -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_shared(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "handle")) { - auto prop = value.getProperty(runtime, "handle"); - // The native buffer pointer arrives as a BigInt (uintptr_t value). It - // must be a BigInt: a JS number can't represent a 64-bit pointer - // without truncation, so we reject it rather than corrupt the address. - if (prop.isBigInt()) { - result->handle = prop.asBigInt(runtime).asUint64(runtime); - } else if (!prop.isUndefined() && !prop.isNull()) { - throw jsi::JSError( - runtime, "GPUSharedTextureMemoryDescriptor.handle must be a " - "NativeBuffer (BigInt) from " - "Skia.NativeBuffer.MakeFromImage / MakeTestBuffer"); - } - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - if (!prop.isUndefined()) { - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - } - return result; - } - static jsi::Value - toJSI(jsi::Runtime & /*runtime*/, - std::shared_ptr /*arg*/) { - throw std::runtime_error( - "Invalid GPUSharedTextureMemoryDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h deleted file mode 100644 index febe8f8c99..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUStencilFaceState { - std::optional compare; // GPUCompareFunction - std::optional failOp; // GPUStencilOperation - std::optional depthFailOp; // GPUStencilOperation - std::optional passOp; // GPUStencilOperation -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "compare")) { - auto prop = value.getProperty(runtime, "compare"); - result->compare = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "failOp")) { - auto prop = value.getProperty(runtime, "failOp"); - result->failOp = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "depthFailOp")) { - auto prop = value.getProperty(runtime, "depthFailOp"); - result->depthFailOp = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "passOp")) { - auto prop = value.getProperty(runtime, "passOp"); - result->passOp = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUStencilFaceState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h deleted file mode 100644 index dba068c83a..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUStorageTextureBindingLayout { - std::optional access; // GPUStorageTextureAccess - wgpu::TextureFormat format; // GPUTextureFormat - std::optional - viewDimension; // GPUTextureViewDimension -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "access")) { - auto prop = value.getProperty(runtime, "access"); - result->access = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "viewDimension")) { - auto prop = value.getProperty(runtime, "viewDimension"); - result->viewDimension = - JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUStorageTextureBindingLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h deleted file mode 100644 index ed43e78608..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUTextureBindingLayout { - std::optional sampleType; // GPUTextureSampleType - std::optional - viewDimension; // GPUTextureViewDimension - std::optional multisampled; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "sampleType")) { - auto prop = value.getProperty(runtime, "sampleType"); - result->sampleType = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "viewDimension")) { - auto prop = value.getProperty(runtime, "viewDimension"); - result->viewDimension = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "multisampled")) { - auto prop = value.getProperty(runtime, "multisampled"); - result->multisampled = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUTextureBindingLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h deleted file mode 100644 index dd2fb1d33f..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUExtent3D.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUTextureDescriptor { - std::shared_ptr size; // GPUExtent3DStrict - std::optional mipLevelCount; // GPUIntegerCoordinate - std::optional sampleCount; // GPUSize32 - std::optional dimension; // GPUTextureDimension - wgpu::TextureFormat format; // GPUTextureFormat - double usage; // GPUTextureUsageFlags - std::optional> - viewFormats; // Iterable - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "size")) { - auto prop = value.getProperty(runtime, "size"); - result->size = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "mipLevelCount")) { - auto prop = value.getProperty(runtime, "mipLevelCount"); - result->mipLevelCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "sampleCount")) { - auto prop = value.getProperty(runtime, "sampleCount"); - result->sampleCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "dimension")) { - auto prop = value.getProperty(runtime, "dimension"); - result->dimension = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "usage")) { - auto prop = value.getProperty(runtime, "usage"); - result->usage = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "viewFormats")) { - auto prop = value.getProperty(runtime, "viewFormats"); - result->viewFormats = JSIConverter< - std::optional>>::fromJSI(runtime, - prop, - false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUTextureDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h deleted file mode 100644 index f4c654259f..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { - -namespace jsi = facebook::jsi; - -class GPUTextureUsage { -public: - static jsi::Object create(jsi::Runtime &runtime) { - jsi::Object obj(runtime); - obj.setProperty(runtime, "COPY_SRC", - static_cast(wgpu::TextureUsage::CopySrc)); - obj.setProperty(runtime, "COPY_DST", - static_cast(wgpu::TextureUsage::CopyDst)); - obj.setProperty(runtime, "TEXTURE_BINDING", - static_cast(wgpu::TextureUsage::TextureBinding)); - obj.setProperty(runtime, "STORAGE_BINDING", - static_cast(wgpu::TextureUsage::StorageBinding)); - obj.setProperty(runtime, "RENDER_ATTACHMENT", - static_cast(wgpu::TextureUsage::RenderAttachment)); - return obj; - } -}; - -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h deleted file mode 100644 index 1cb2e597da..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUTextureViewDescriptor { - std::optional format; // GPUTextureFormat - std::optional - dimension; // GPUTextureViewDimension - std::optional aspect; // GPUTextureAspect - std::optional baseMipLevel; // GPUIntegerCoordinate - std::optional mipLevelCount; // GPUIntegerCoordinate - std::optional baseArrayLayer; // GPUIntegerCoordinate - std::optional arrayLayerCount; // GPUIntegerCoordinate - std::optional label; // string -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "dimension")) { - auto prop = value.getProperty(runtime, "dimension"); - result->dimension = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "aspect")) { - auto prop = value.getProperty(runtime, "aspect"); - result->aspect = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "baseMipLevel")) { - auto prop = value.getProperty(runtime, "baseMipLevel"); - result->baseMipLevel = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "mipLevelCount")) { - auto prop = value.getProperty(runtime, "mipLevelCount"); - result->mipLevelCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "baseArrayLayer")) { - auto prop = value.getProperty(runtime, "baseArrayLayer"); - result->baseArrayLayer = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "arrayLayerCount")) { - auto prop = value.getProperty(runtime, "arrayLayerCount"); - result->arrayLayerCount = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "label")) { - auto prop = value.getProperty(runtime, "label"); - result->label = JSIConverter>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUTextureViewDescriptor::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h deleted file mode 100644 index 74917ac7f9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "rnwgpu/api/GPUError.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUUncapturedErrorEventInit { - std::shared_ptr error; // GPUError - std::optional bubbles; // boolean - std::optional cancelable; // boolean - std::optional composed; // boolean -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "error")) { - auto prop = value.getProperty(runtime, "error"); - result->error = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "bubbles")) { - auto prop = value.getProperty(runtime, "bubbles"); - result->bubbles = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "cancelable")) { - auto prop = value.getProperty(runtime, "cancelable"); - result->cancelable = - JSIConverter>::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "composed")) { - auto prop = value.getProperty(runtime, "composed"); - result->composed = - JSIConverter>::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value - toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUUncapturedErrorEventInit::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h deleted file mode 100644 index 3ca2bddd12..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUVertexAttribute { - wgpu::VertexFormat format; // GPUVertexFormat - double offset; // GPUSize64 - double shaderLocation; // GPUIndex32 -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "format")) { - auto prop = value.getProperty(runtime, "format"); - result->format = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "offset")) { - auto prop = value.getProperty(runtime, "offset"); - result->offset = JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "shaderLocation")) { - auto prop = value.getProperty(runtime, "shaderLocation"); - result->shaderLocation = - JSIConverter::fromJSI(runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUVertexAttribute::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h deleted file mode 100644 index d64cf4ca34..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUVertexAttribute.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUVertexBufferLayout { - double arrayStride; // GPUSize64 - std::optional stepMode; // GPUVertexStepMode - std::vector> - attributes; // Iterable -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> -struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "arrayStride")) { - auto prop = value.getProperty(runtime, "arrayStride"); - result->arrayStride = - JSIConverter::fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "stepMode")) { - auto prop = value.getProperty(runtime, "stepMode"); - result->stepMode = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "attributes")) { - auto prop = value.getProperty(runtime, "attributes"); - result->attributes = JSIConverter< - std::vector>>::fromJSI(runtime, - prop, - false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUVertexBufferLayout::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexState.h b/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexState.h deleted file mode 100644 index 84934d0e98..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/GPUVertexState.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "webgpu/webgpu_cpp.h" - -#include "jsi/JSIConverter.h" - -#include "GPUVertexBufferLayout.h" -#include "rnwgpu/api/GPUShaderModule.h" - -namespace jsi = facebook::jsi; - -namespace rnwgpu { - -struct GPUVertexState { - std::optional>>> - buffers; // Iterable - std::shared_ptr module; // GPUShaderModule - std::optional entryPoint; // string - std::optional> - constants; // Record< string, GPUPipelineConstantValue > -}; - -} // namespace rnwgpu - -namespace rnwgpu { - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - auto result = std::make_unique(); - if (!outOfBounds && arg.isObject()) { - auto value = arg.getObject(runtime); - if (value.hasProperty(runtime, "buffers")) { - auto prop = value.getProperty(runtime, "buffers"); - result->buffers = JSIConverter>>>>:: - fromJSI(runtime, prop, false); - } - if (value.hasProperty(runtime, "module")) { - auto prop = value.getProperty(runtime, "module"); - result->module = - JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "entryPoint")) { - auto prop = value.getProperty(runtime, "entryPoint"); - result->entryPoint = JSIConverter>::fromJSI( - runtime, prop, false); - } - if (value.hasProperty(runtime, "constants")) { - auto prop = value.getProperty(runtime, "constants"); - result->constants = - JSIConverter>>::fromJSI( - runtime, prop, false); - } - } - - return result; - } - static jsi::Value toJSI(jsi::Runtime &runtime, - std::shared_ptr arg) { - throw std::runtime_error("Invalid GPUVertexState::toJSI()"); - } -}; - -} // namespace rnwgpu \ No newline at end of file diff --git a/packages/skia/cpp/rnwgpu/api/descriptors/Unions.h b/packages/skia/cpp/rnwgpu/api/descriptors/Unions.h deleted file mode 100644 index b5551214b9..0000000000 --- a/packages/skia/cpp/rnwgpu/api/descriptors/Unions.h +++ /dev/null @@ -1,1969 +0,0 @@ -#pragma once - -#include - -#include "jsi/EnumMapper.h" -#include "rnwgpu/api/External.h" -#include "webgpu/webgpu_cpp.h" - -namespace rnwgpu { -namespace EnumMapper { - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::AddressMode *outEnum) { - if (inUnion == "clamp-to-edge") { - *outEnum = wgpu::AddressMode::ClampToEdge; - } else if (inUnion == "repeat") { - *outEnum = wgpu::AddressMode::Repeat; - } else if (inUnion == "mirror-repeat") { - *outEnum = wgpu::AddressMode::MirrorRepeat; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::AddressMode inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::AddressMode::ClampToEdge: - *outUnion = "clamp-to-edge"; - break; - case wgpu::AddressMode::Repeat: - *outUnion = "repeat"; - break; - case wgpu::AddressMode::MirrorRepeat: - *outUnion = "mirror-repeat"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::BlendFactor *outEnum) { - if (inUnion == "zero") { - *outEnum = wgpu::BlendFactor::Zero; - } else if (inUnion == "one") { - *outEnum = wgpu::BlendFactor::One; - } else if (inUnion == "src") { - *outEnum = wgpu::BlendFactor::Src; - } else if (inUnion == "one-minus-src") { - *outEnum = wgpu::BlendFactor::OneMinusSrc; - } else if (inUnion == "src-alpha") { - *outEnum = wgpu::BlendFactor::SrcAlpha; - } else if (inUnion == "one-minus-src-alpha") { - *outEnum = wgpu::BlendFactor::OneMinusSrcAlpha; - } else if (inUnion == "dst") { - *outEnum = wgpu::BlendFactor::Dst; - } else if (inUnion == "one-minus-dst") { - *outEnum = wgpu::BlendFactor::OneMinusDst; - } else if (inUnion == "dst-alpha") { - *outEnum = wgpu::BlendFactor::DstAlpha; - } else if (inUnion == "one-minus-dst-alpha") { - *outEnum = wgpu::BlendFactor::OneMinusDstAlpha; - } else if (inUnion == "src-alpha-saturated") { - *outEnum = wgpu::BlendFactor::SrcAlphaSaturated; - } else if (inUnion == "constant") { - *outEnum = wgpu::BlendFactor::Constant; - } else if (inUnion == "one-minus-constant") { - *outEnum = wgpu::BlendFactor::OneMinusConstant; - } else if (inUnion == "src1") { - *outEnum = wgpu::BlendFactor::Src1; - } else if (inUnion == "one-minus-src1") { - *outEnum = wgpu::BlendFactor::OneMinusSrc1; - } else if (inUnion == "src1-alpha") { - *outEnum = wgpu::BlendFactor::Src1Alpha; - } else if (inUnion == "one-minus-src1-alpha") { - *outEnum = wgpu::BlendFactor::OneMinusSrc1Alpha; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::BlendFactor inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::BlendFactor::Zero: - *outUnion = "zero"; - break; - case wgpu::BlendFactor::One: - *outUnion = "one"; - break; - case wgpu::BlendFactor::Src: - *outUnion = "src"; - break; - case wgpu::BlendFactor::OneMinusSrc: - *outUnion = "one-minus-src"; - break; - case wgpu::BlendFactor::SrcAlpha: - *outUnion = "src-alpha"; - break; - case wgpu::BlendFactor::OneMinusSrcAlpha: - *outUnion = "one-minus-src-alpha"; - break; - case wgpu::BlendFactor::Dst: - *outUnion = "dst"; - break; - case wgpu::BlendFactor::OneMinusDst: - *outUnion = "one-minus-dst"; - break; - case wgpu::BlendFactor::DstAlpha: - *outUnion = "dst-alpha"; - break; - case wgpu::BlendFactor::OneMinusDstAlpha: - *outUnion = "one-minus-dst-alpha"; - break; - case wgpu::BlendFactor::SrcAlphaSaturated: - *outUnion = "src-alpha-saturated"; - break; - case wgpu::BlendFactor::Constant: - *outUnion = "constant"; - break; - case wgpu::BlendFactor::OneMinusConstant: - *outUnion = "one-minus-constant"; - break; - case wgpu::BlendFactor::Src1: - *outUnion = "src1"; - break; - case wgpu::BlendFactor::OneMinusSrc1: - *outUnion = "one-minus-src1"; - break; - case wgpu::BlendFactor::Src1Alpha: - *outUnion = "src1-alpha"; - break; - case wgpu::BlendFactor::OneMinusSrc1Alpha: - *outUnion = "one-minus-src1-alpha"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::BlendOperation *outEnum) { - if (inUnion == "add") { - *outEnum = wgpu::BlendOperation::Add; - } else if (inUnion == "subtract") { - *outEnum = wgpu::BlendOperation::Subtract; - } else if (inUnion == "reverse-subtract") { - *outEnum = wgpu::BlendOperation::ReverseSubtract; - } else if (inUnion == "min") { - *outEnum = wgpu::BlendOperation::Min; - } else if (inUnion == "max") { - *outEnum = wgpu::BlendOperation::Max; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::BlendOperation inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::BlendOperation::Add: - *outUnion = "add"; - break; - case wgpu::BlendOperation::Subtract: - *outUnion = "subtract"; - break; - case wgpu::BlendOperation::ReverseSubtract: - *outUnion = "reverse-subtract"; - break; - case wgpu::BlendOperation::Min: - *outUnion = "min"; - break; - case wgpu::BlendOperation::Max: - *outUnion = "max"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::BufferBindingType *outEnum) { - if (inUnion == "uniform") { - *outEnum = wgpu::BufferBindingType::Uniform; - } else if (inUnion == "storage") { - *outEnum = wgpu::BufferBindingType::Storage; - } else if (inUnion == "read-only-storage") { - *outEnum = wgpu::BufferBindingType::ReadOnlyStorage; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::BufferBindingType inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::BufferBindingType::Uniform: - *outUnion = "uniform"; - break; - case wgpu::BufferBindingType::Storage: - *outUnion = "storage"; - break; - case wgpu::BufferBindingType::ReadOnlyStorage: - *outUnion = "read-only-storage"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::BufferMapState *outEnum) { - if (inUnion == "unmapped") { - *outEnum = wgpu::BufferMapState::Unmapped; - } else if (inUnion == "pending") { - *outEnum = wgpu::BufferMapState::Pending; - } else if (inUnion == "mapped") { - *outEnum = wgpu::BufferMapState::Mapped; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::BufferMapState inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::BufferMapState::Unmapped: - *outUnion = "unmapped"; - break; - case wgpu::BufferMapState::Pending: - *outUnion = "pending"; - break; - case wgpu::BufferMapState::Mapped: - *outUnion = "mapped"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::CompareFunction *outEnum) { - if (inUnion == "never") { - *outEnum = wgpu::CompareFunction::Never; - } else if (inUnion == "less") { - *outEnum = wgpu::CompareFunction::Less; - } else if (inUnion == "equal") { - *outEnum = wgpu::CompareFunction::Equal; - } else if (inUnion == "less-equal") { - *outEnum = wgpu::CompareFunction::LessEqual; - } else if (inUnion == "greater") { - *outEnum = wgpu::CompareFunction::Greater; - } else if (inUnion == "not-equal") { - *outEnum = wgpu::CompareFunction::NotEqual; - } else if (inUnion == "greater-equal") { - *outEnum = wgpu::CompareFunction::GreaterEqual; - } else if (inUnion == "always") { - *outEnum = wgpu::CompareFunction::Always; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::CompareFunction inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::CompareFunction::Never: - *outUnion = "never"; - break; - case wgpu::CompareFunction::Less: - *outUnion = "less"; - break; - case wgpu::CompareFunction::Equal: - *outUnion = "equal"; - break; - case wgpu::CompareFunction::LessEqual: - *outUnion = "less-equal"; - break; - case wgpu::CompareFunction::Greater: - *outUnion = "greater"; - break; - case wgpu::CompareFunction::NotEqual: - *outUnion = "not-equal"; - break; - case wgpu::CompareFunction::GreaterEqual: - *outUnion = "greater-equal"; - break; - case wgpu::CompareFunction::Always: - *outUnion = "always"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::CompilationMessageType *outEnum) { - if (inUnion == "error") { - *outEnum = wgpu::CompilationMessageType::Error; - } else if (inUnion == "warning") { - *outEnum = wgpu::CompilationMessageType::Warning; - } else if (inUnion == "info") { - *outEnum = wgpu::CompilationMessageType::Info; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::CompilationMessageType inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::CompilationMessageType::Error: - *outUnion = "error"; - break; - case wgpu::CompilationMessageType::Warning: - *outUnion = "warning"; - break; - case wgpu::CompilationMessageType::Info: - *outUnion = "info"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::CullMode *outEnum) { - if (inUnion == "none") { - *outEnum = wgpu::CullMode::None; - } else if (inUnion == "front") { - *outEnum = wgpu::CullMode::Front; - } else if (inUnion == "back") { - *outEnum = wgpu::CullMode::Back; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::CullMode inEnum, std::string *outUnion) { - switch (inEnum) { - case wgpu::CullMode::None: - *outUnion = "none"; - break; - case wgpu::CullMode::Front: - *outUnion = "front"; - break; - case wgpu::CullMode::Back: - *outUnion = "back"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::DeviceLostReason *outEnum) { - if (inUnion == "unknown") { - *outEnum = wgpu::DeviceLostReason::Unknown; - } else if (inUnion == "destroyed") { - *outEnum = wgpu::DeviceLostReason::Destroyed; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::DeviceLostReason inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::DeviceLostReason::Unknown: - *outUnion = "unknown"; - break; - case wgpu::DeviceLostReason::Destroyed: - *outUnion = "destroyed"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::ErrorFilter *outEnum) { - if (inUnion == "validation") { - *outEnum = wgpu::ErrorFilter::Validation; - } else if (inUnion == "out-of-memory") { - *outEnum = wgpu::ErrorFilter::OutOfMemory; - } else if (inUnion == "internal") { - *outEnum = wgpu::ErrorFilter::Internal; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::ErrorFilter inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::ErrorFilter::Validation: - *outUnion = "validation"; - break; - case wgpu::ErrorFilter::OutOfMemory: - *outUnion = "out-of-memory"; - break; - case wgpu::ErrorFilter::Internal: - *outUnion = "internal"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::FeatureName *outEnum) { - if (inUnion == "depth-clip-control") { - *outEnum = wgpu::FeatureName::DepthClipControl; - } else if (inUnion == "depth32float-stencil8") { - *outEnum = wgpu::FeatureName::Depth32FloatStencil8; - } else if (inUnion == "texture-compression-bc") { - *outEnum = wgpu::FeatureName::TextureCompressionBC; - } else if (inUnion == "texture-compression-etc2") { - *outEnum = wgpu::FeatureName::TextureCompressionETC2; - } else if (inUnion == "texture-compression-astc") { - *outEnum = wgpu::FeatureName::TextureCompressionASTC; - } else if (inUnion == "timestamp-query") { - *outEnum = wgpu::FeatureName::TimestampQuery; - } else if (inUnion == "indirect-first-instance") { - *outEnum = wgpu::FeatureName::IndirectFirstInstance; - } else if (inUnion == "shader-f16") { - *outEnum = wgpu::FeatureName::ShaderF16; - } else if (inUnion == "rg11b10ufloat-renderable") { - *outEnum = wgpu::FeatureName::RG11B10UfloatRenderable; - } else if (inUnion == "bgra8unorm-storage") { - *outEnum = wgpu::FeatureName::BGRA8UnormStorage; - } else if (inUnion == "float32-filterable") { - *outEnum = wgpu::FeatureName::Float32Filterable; - } else if (inUnion == "subgroups") { - *outEnum = wgpu::FeatureName::Subgroups; - } else if (inUnion == "dawn-internal-usages") { - *outEnum = wgpu::FeatureName::DawnInternalUsages; - } else if (inUnion == "dawn-multi-planar-formats") { - *outEnum = wgpu::FeatureName::DawnMultiPlanarFormats; - } else if (inUnion == "dawn-native") { - *outEnum = wgpu::FeatureName::DawnNative; - } else if (inUnion == "chromium-experimental-timestamp-query-inside-passes") { - *outEnum = - wgpu::FeatureName::ChromiumExperimentalTimestampQueryInsidePasses; - } else if (inUnion == "implicit-device-synchronization") { - *outEnum = wgpu::FeatureName::ImplicitDeviceSynchronization; - } else if (inUnion == "transient-attachments") { - *outEnum = wgpu::FeatureName::TransientAttachments; - } else if (inUnion == "msaa-render-to-single-sampled") { - *outEnum = wgpu::FeatureName::MSAARenderToSingleSampled; - } else if (inUnion == "dual-source-blending") { - *outEnum = wgpu::FeatureName::DualSourceBlending; - } else if (inUnion == "d3d11-multithread-protected") { - *outEnum = wgpu::FeatureName::D3D11MultithreadProtected; - } else if (inUnion == "angle-texture-sharing") { - *outEnum = wgpu::FeatureName::ANGLETextureSharing; - } else if (inUnion == "chromium-experimental-subgroups-matrix") { - *outEnum = wgpu::FeatureName::ChromiumExperimentalSubgroupMatrix; - } else if (inUnion == "pixel-local-storage-coherent") { - *outEnum = wgpu::FeatureName::PixelLocalStorageCoherent; - } else if (inUnion == "pixel-local-storage-non-coherent") { - *outEnum = wgpu::FeatureName::PixelLocalStorageNonCoherent; - } else if (inUnion == "unorm16-texture-formats") { - *outEnum = wgpu::FeatureName::Unorm16TextureFormats; - } else if (inUnion == "multi-planar-format-extended-usages") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatExtendedUsages; - } else if (inUnion == "multi-planar-format-p010") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatP010; - } else if (inUnion == "host-mapped-pointer") { - *outEnum = wgpu::FeatureName::HostMappedPointer; - } else if (inUnion == "multi-planar-render-targets") { - *outEnum = wgpu::FeatureName::MultiPlanarRenderTargets; - } else if (inUnion == "multi-planar-format-nv12a") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatNv12a; - } else if (inUnion == "framebuffer-fetch") { - *outEnum = wgpu::FeatureName::FramebufferFetch; - } else if (inUnion == "buffer-map-extended-usages") { - *outEnum = wgpu::FeatureName::BufferMapExtendedUsages; - } else if (inUnion == "adapter-properties-memory-heaps") { - *outEnum = wgpu::FeatureName::AdapterPropertiesMemoryHeaps; - } else if (inUnion == "adapter-properties-d3d") { - *outEnum = wgpu::FeatureName::AdapterPropertiesD3D; - } else if (inUnion == "adapter-properties-vk") { - *outEnum = wgpu::FeatureName::AdapterPropertiesVk; - } else if (inUnion == "format-capabilities") { - *outEnum = wgpu::FeatureName::DawnFormatCapabilities; - } else if (inUnion == "multi-planar-format-nv16") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatNv16; - } else if (inUnion == "multi-planar-format-nv24") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatNv24; - } else if (inUnion == "multi-planar-format-p210") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatP210; - } else if (inUnion == "multi-planar-format-p410") { - *outEnum = wgpu::FeatureName::MultiPlanarFormatP410; - } else if (inUnion == "shared-texture-memory-vk-dedicated-allocation") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryVkDedicatedAllocation; - } else if (inUnion == "shared-texture-memory-ahardware-buffer") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer; - } else if (inUnion == "shared-texture-memory-dma-buf") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryDmaBuf; - } else if (inUnion == "shared-texture-memory-opaque-fd") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryOpaqueFD; - } else if (inUnion == "shared-texture-memory-zircon-handle") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryZirconHandle; - } else if (inUnion == "shared-texture-memory-dxgi-shared-handle") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle; - } else if (inUnion == "shared-texture-memory-d3d11-texture2d") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D; - } else if (inUnion == "shared-texture-memory-iosurface") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryIOSurface; - } else if (inUnion == "shared-texture-memory-egl-image") { - *outEnum = wgpu::FeatureName::SharedTextureMemoryEGLImage; - } else if (inUnion == "shared-fence-vk-semaphore-opaque-fd") { - *outEnum = wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD; - } else if (inUnion == "shared-fence-vk-semaphore-zircon-handle") { - *outEnum = wgpu::FeatureName::SharedFenceVkSemaphoreZirconHandle; - } else if (inUnion == "shared-fence-dxgi-shared-handle") { - *outEnum = wgpu::FeatureName::SharedFenceDXGISharedHandle; - } else if (inUnion == "shared-fence-mtl-shared-event") { - *outEnum = wgpu::FeatureName::SharedFenceMTLSharedEvent; - } else if (inUnion == "shared-buffer-memory-d3d12-resource") { - *outEnum = wgpu::FeatureName::SharedBufferMemoryD3D12Resource; - } else if (inUnion == "static-samplers") { - *outEnum = wgpu::FeatureName::StaticSamplers; - } else if (inUnion == "ycbcr-vulkan-samplers") { - *outEnum = wgpu::FeatureName::YCbCrVulkanSamplers; - } else if (inUnion == "shader-module-compilation-options") { - *outEnum = wgpu::FeatureName::ShaderModuleCompilationOptions; - } else if (inUnion == "dawn-load-resolve-texture") { - *outEnum = wgpu::FeatureName::DawnLoadResolveTexture; - } else if (inUnion == "clip-distances") { - *outEnum = wgpu::FeatureName::ClipDistances; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::FeatureName inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::FeatureName::DepthClipControl: - *outUnion = "depth-clip-control"; - break; - case wgpu::FeatureName::Depth32FloatStencil8: - *outUnion = "depth32float-stencil8"; - break; - case wgpu::FeatureName::TextureCompressionBC: - *outUnion = "texture-compression-bc"; - break; - case wgpu::FeatureName::TextureCompressionETC2: - *outUnion = "texture-compression-etc2"; - break; - case wgpu::FeatureName::TextureCompressionASTC: - *outUnion = "texture-compression-astc"; - break; - case wgpu::FeatureName::TimestampQuery: - *outUnion = "timestamp-query"; - break; - case wgpu::FeatureName::IndirectFirstInstance: - *outUnion = "indirect-first-instance"; - break; - case wgpu::FeatureName::ShaderF16: - *outUnion = "shader-f16"; - break; - case wgpu::FeatureName::RG11B10UfloatRenderable: - *outUnion = "rg11b10ufloat-renderable"; - break; - case wgpu::FeatureName::BGRA8UnormStorage: - *outUnion = "bgra8unorm-storage"; - break; - case wgpu::FeatureName::Float32Filterable: - *outUnion = "float32-filterable"; - break; - case wgpu::FeatureName::Subgroups: - *outUnion = "subgroups"; - break; - case wgpu::FeatureName::DawnInternalUsages: - *outUnion = "dawn-internal-usages"; - break; - case wgpu::FeatureName::DawnMultiPlanarFormats: - *outUnion = "dawn-multi-planar-formats"; - break; - case wgpu::FeatureName::DawnNative: - *outUnion = "dawn-native"; - break; - case wgpu::FeatureName::DawnFormatCapabilities: - *outUnion = "format-capabilities"; - break; - case wgpu::FeatureName::ChromiumExperimentalTimestampQueryInsidePasses: - *outUnion = "chromium-experimental-timestamp-query-inside-passes"; - break; - case wgpu::FeatureName::ImplicitDeviceSynchronization: - *outUnion = "implicit-device-synchronization"; - break; - // case wgpu::FeatureName::SurfaceCapabilities: - // *outUnion = "surface-capabilities"; - // break; - case wgpu::FeatureName::TransientAttachments: - *outUnion = "transient-attachments"; - break; - case wgpu::FeatureName::MSAARenderToSingleSampled: - *outUnion = "msaa-render-to-single-sampled"; - break; - case wgpu::FeatureName::DualSourceBlending: - *outUnion = "dual-source-blending"; - break; - case wgpu::FeatureName::D3D11MultithreadProtected: - *outUnion = "d3d11-multithread-protected"; - break; - case wgpu::FeatureName::ANGLETextureSharing: - *outUnion = "angle-texture-sharing"; - break; - case wgpu::FeatureName::ChromiumExperimentalSubgroupMatrix: - *outUnion = "chromium-experimental-subgroups-matrix"; - break; - case wgpu::FeatureName::PixelLocalStorageCoherent: - *outUnion = "pixel-local-storage-coherent"; - break; - case wgpu::FeatureName::PixelLocalStorageNonCoherent: - *outUnion = "pixel-local-storage-non-coherent"; - break; - case wgpu::FeatureName::Unorm16TextureFormats: - *outUnion = "unorm16-texture-formats"; - break; - case wgpu::FeatureName::MultiPlanarFormatExtendedUsages: - *outUnion = "multi-planar-format-extended-usages"; - break; - case wgpu::FeatureName::MultiPlanarFormatP010: - *outUnion = "multi-planar-format-p010"; - break; - case wgpu::FeatureName::HostMappedPointer: - *outUnion = "host-mapped-pointer"; - break; - case wgpu::FeatureName::MultiPlanarRenderTargets: - *outUnion = "multi-planar-render-targets"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv12a: - *outUnion = "multi-planar-format-nv12a"; - break; - case wgpu::FeatureName::FramebufferFetch: - *outUnion = "framebuffer-fetch"; - break; - case wgpu::FeatureName::BufferMapExtendedUsages: - *outUnion = "buffer-map-extended-usages"; - break; - case wgpu::FeatureName::AdapterPropertiesMemoryHeaps: - *outUnion = "adapter-properties-memory-heaps"; - break; - case wgpu::FeatureName::AdapterPropertiesD3D: - *outUnion = "adapter-properties-d3d"; - break; - case wgpu::FeatureName::AdapterPropertiesVk: - *outUnion = "adapter-properties-vk"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv16: - *outUnion = "multi-planar-format-nv16"; - break; - case wgpu::FeatureName::MultiPlanarFormatNv24: - *outUnion = "multi-planar-format-nv24"; - break; - case wgpu::FeatureName::MultiPlanarFormatP210: - *outUnion = "multi-planar-format-p210"; - break; - case wgpu::FeatureName::MultiPlanarFormatP410: - *outUnion = "multi-planar-format-p410"; - break; - case wgpu::FeatureName::SharedTextureMemoryVkDedicatedAllocation: - *outUnion = "shared-texture-memory-vk-dedicated-allocation"; - break; - case wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer: - *outUnion = "shared-texture-memory-ahardware-buffer"; - break; - case wgpu::FeatureName::SharedTextureMemoryDmaBuf: - *outUnion = "shared-texture-memory-dma-buf"; - break; - case wgpu::FeatureName::SharedTextureMemoryOpaqueFD: - *outUnion = "shared-texture-memory-opaque-fd"; - break; - case wgpu::FeatureName::SharedTextureMemoryZirconHandle: - *outUnion = "shared-texture-memory-zircon-handle"; - break; - case wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle: - *outUnion = "shared-texture-memory-dxgi-shared-handle"; - break; - case wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D: - *outUnion = "shared-texture-memory-d3d11-texture2d"; - break; - case wgpu::FeatureName::SharedTextureMemoryIOSurface: - *outUnion = "shared-texture-memory-iosurface"; - break; - case wgpu::FeatureName::SharedTextureMemoryEGLImage: - *outUnion = "shared-texture-memory-egl-image"; - break; - case wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD: - *outUnion = "shared-fence-vk-semaphore-opaque-fd"; - break; - case wgpu::FeatureName::SharedFenceVkSemaphoreZirconHandle: - *outUnion = "shared-fence-vk-semaphore-zircon-handle"; - break; - case wgpu::FeatureName::SharedFenceDXGISharedHandle: - *outUnion = "shared-fence-dxgi-shared-handle"; - break; - case wgpu::FeatureName::SharedFenceMTLSharedEvent: - *outUnion = "shared-fence-mtl-shared-event"; - break; - case wgpu::FeatureName::SharedBufferMemoryD3D12Resource: - *outUnion = "shared-buffer-memory-d3d12-resource"; - break; - case wgpu::FeatureName::StaticSamplers: - *outUnion = "static-samplers"; - break; - case wgpu::FeatureName::YCbCrVulkanSamplers: - *outUnion = "ycbcr-vulkan-samplers"; - break; - case wgpu::FeatureName::ShaderModuleCompilationOptions: - *outUnion = "shader-module-compilation-options"; - break; - case wgpu::FeatureName::DawnLoadResolveTexture: - *outUnion = "dawn-load-resolve-texture"; - break; - case wgpu::FeatureName::ClipDistances: - *outUnion = "clip-distances"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::FilterMode *outEnum) { - if (inUnion == "nearest") { - *outEnum = wgpu::FilterMode::Nearest; - } else if (inUnion == "linear") { - *outEnum = wgpu::FilterMode::Linear; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::FilterMode inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::FilterMode::Nearest: - *outUnion = "nearest"; - break; - case wgpu::FilterMode::Linear: - *outUnion = "linear"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::FrontFace *outEnum) { - if (inUnion == "ccw") { - *outEnum = wgpu::FrontFace::CCW; - } else if (inUnion == "cw") { - *outEnum = wgpu::FrontFace::CW; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::FrontFace inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::FrontFace::CCW: - *outUnion = "ccw"; - break; - case wgpu::FrontFace::CW: - *outUnion = "cw"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::IndexFormat *outEnum) { - if (inUnion == "uint16") { - *outEnum = wgpu::IndexFormat::Uint16; - } else if (inUnion == "uint32") { - *outEnum = wgpu::IndexFormat::Uint32; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::IndexFormat inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::IndexFormat::Uint16: - *outUnion = "uint16"; - break; - case wgpu::IndexFormat::Uint32: - *outUnion = "uint32"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::LoadOp *outEnum) { - if (inUnion == "load") { - *outEnum = wgpu::LoadOp::Load; - } else if (inUnion == "clear") { - *outEnum = wgpu::LoadOp::Clear; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::LoadOp inEnum, std::string *outUnion) { - switch (inEnum) { - case wgpu::LoadOp::Load: - *outUnion = "load"; - break; - case wgpu::LoadOp::Clear: - *outUnion = "clear"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::MipmapFilterMode *outEnum) { - if (inUnion == "nearest") { - *outEnum = wgpu::MipmapFilterMode::Nearest; - } else if (inUnion == "linear") { - *outEnum = wgpu::MipmapFilterMode::Linear; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::MipmapFilterMode inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::MipmapFilterMode::Nearest: - *outUnion = "nearest"; - break; - case wgpu::MipmapFilterMode::Linear: - *outUnion = "linear"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::PowerPreference *outEnum) { - if (inUnion == "low-power") { - *outEnum = wgpu::PowerPreference::LowPower; - } else if (inUnion == "high-performance") { - *outEnum = wgpu::PowerPreference::HighPerformance; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::PowerPreference inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::PowerPreference::LowPower: - *outUnion = "low-power"; - break; - case wgpu::PowerPreference::HighPerformance: - *outUnion = "high-performance"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::PrimitiveTopology *outEnum) { - if (inUnion == "point-list") { - *outEnum = wgpu::PrimitiveTopology::PointList; - } else if (inUnion == "line-list") { - *outEnum = wgpu::PrimitiveTopology::LineList; - } else if (inUnion == "line-strip") { - *outEnum = wgpu::PrimitiveTopology::LineStrip; - } else if (inUnion == "triangle-list") { - *outEnum = wgpu::PrimitiveTopology::TriangleList; - } else if (inUnion == "triangle-strip") { - *outEnum = wgpu::PrimitiveTopology::TriangleStrip; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::PrimitiveTopology inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::PrimitiveTopology::PointList: - *outUnion = "point-list"; - break; - case wgpu::PrimitiveTopology::LineList: - *outUnion = "line-list"; - break; - case wgpu::PrimitiveTopology::LineStrip: - *outUnion = "line-strip"; - break; - case wgpu::PrimitiveTopology::TriangleList: - *outUnion = "triangle-list"; - break; - case wgpu::PrimitiveTopology::TriangleStrip: - *outUnion = "triangle-strip"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::QueryType *outEnum) { - if (inUnion == "occlusion") { - *outEnum = wgpu::QueryType::Occlusion; - } else if (inUnion == "timestamp") { - *outEnum = wgpu::QueryType::Timestamp; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::QueryType inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::QueryType::Occlusion: - *outUnion = "occlusion"; - break; - case wgpu::QueryType::Timestamp: - *outUnion = "timestamp"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::SamplerBindingType *outEnum) { - if (inUnion == "filtering") { - *outEnum = wgpu::SamplerBindingType::Filtering; - } else if (inUnion == "non-filtering") { - *outEnum = wgpu::SamplerBindingType::NonFiltering; - } else if (inUnion == "comparison") { - *outEnum = wgpu::SamplerBindingType::Comparison; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::SamplerBindingType inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::SamplerBindingType::Filtering: - *outUnion = "filtering"; - break; - case wgpu::SamplerBindingType::NonFiltering: - *outUnion = "non-filtering"; - break; - case wgpu::SamplerBindingType::Comparison: - *outUnion = "comparison"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::StencilOperation *outEnum) { - if (inUnion == "zero") { - *outEnum = wgpu::StencilOperation::Zero; - } else if (inUnion == "keep") { - *outEnum = wgpu::StencilOperation::Keep; - } else if (inUnion == "replace") { - *outEnum = wgpu::StencilOperation::Replace; - } else if (inUnion == "invert") { - *outEnum = wgpu::StencilOperation::Invert; - } else if (inUnion == "increment-clamp") { - *outEnum = wgpu::StencilOperation::IncrementClamp; - } else if (inUnion == "decrement-clamp") { - *outEnum = wgpu::StencilOperation::DecrementClamp; - } else if (inUnion == "increment-wrap") { - *outEnum = wgpu::StencilOperation::IncrementWrap; - } else if (inUnion == "decrement-wrap") { - *outEnum = wgpu::StencilOperation::DecrementWrap; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::StencilOperation inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::StencilOperation::Zero: - *outUnion = "zero"; - break; - case wgpu::StencilOperation::Keep: - *outUnion = "keep"; - break; - case wgpu::StencilOperation::Replace: - *outUnion = "replace"; - break; - case wgpu::StencilOperation::Invert: - *outUnion = "invert"; - break; - case wgpu::StencilOperation::IncrementClamp: - *outUnion = "increment-clamp"; - break; - case wgpu::StencilOperation::DecrementClamp: - *outUnion = "decrement-clamp"; - break; - case wgpu::StencilOperation::IncrementWrap: - *outUnion = "increment-wrap"; - break; - case wgpu::StencilOperation::DecrementWrap: - *outUnion = "decrement-wrap"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::StorageTextureAccess *outEnum) { - if (inUnion == "write-only") { - *outEnum = wgpu::StorageTextureAccess::WriteOnly; - } else if (inUnion == "read-only") { - *outEnum = wgpu::StorageTextureAccess::ReadOnly; - } else if (inUnion == "read-write") { - *outEnum = wgpu::StorageTextureAccess::ReadWrite; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::StorageTextureAccess inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::StorageTextureAccess::WriteOnly: - *outUnion = "write-only"; - break; - case wgpu::StorageTextureAccess::ReadOnly: - *outUnion = "read-only"; - break; - case wgpu::StorageTextureAccess::ReadWrite: - *outUnion = "read-write"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::StoreOp *outEnum) { - if (inUnion == "store") { - *outEnum = wgpu::StoreOp::Store; - } else if (inUnion == "discard") { - *outEnum = wgpu::StoreOp::Discard; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::StoreOp inEnum, std::string *outUnion) { - switch (inEnum) { - case wgpu::StoreOp::Store: - *outUnion = "store"; - break; - case wgpu::StoreOp::Discard: - *outUnion = "discard"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::TextureAspect *outEnum) { - if (inUnion == "all") { - *outEnum = wgpu::TextureAspect::All; - } else if (inUnion == "stencil-only") { - *outEnum = wgpu::TextureAspect::StencilOnly; - } else if (inUnion == "depth-only") { - *outEnum = wgpu::TextureAspect::DepthOnly; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::TextureAspect inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::TextureAspect::All: - *outUnion = "all"; - break; - case wgpu::TextureAspect::StencilOnly: - *outUnion = "stencil-only"; - break; - case wgpu::TextureAspect::DepthOnly: - *outUnion = "depth-only"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::TextureDimension *outEnum) { - if (inUnion == "1d") { - *outEnum = wgpu::TextureDimension::e1D; - } else if (inUnion == "2d") { - *outEnum = wgpu::TextureDimension::e2D; - } else if (inUnion == "3d") { - *outEnum = wgpu::TextureDimension::e3D; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::TextureDimension inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::TextureDimension::e1D: - *outUnion = "1d"; - break; - case wgpu::TextureDimension::e2D: - *outUnion = "2d"; - break; - case wgpu::TextureDimension::e3D: - *outUnion = "3d"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::TextureFormat *outEnum) { - if (inUnion == "depth32float-stencil8") { - *outEnum = wgpu::TextureFormat::Depth32FloatStencil8; - } else if (inUnion == "r8unorm") { - *outEnum = wgpu::TextureFormat::R8Unorm; - } else if (inUnion == "r8snorm") { - *outEnum = wgpu::TextureFormat::R8Snorm; - } else if (inUnion == "r8uint") { - *outEnum = wgpu::TextureFormat::R8Uint; - } else if (inUnion == "r8sint") { - *outEnum = wgpu::TextureFormat::R8Sint; - } else if (inUnion == "r16uint") { - *outEnum = wgpu::TextureFormat::R16Uint; - } else if (inUnion == "r16sint") { - *outEnum = wgpu::TextureFormat::R16Sint; - } else if (inUnion == "r16float") { - *outEnum = wgpu::TextureFormat::R16Float; - } else if (inUnion == "rg8unorm") { - *outEnum = wgpu::TextureFormat::RG8Unorm; - } else if (inUnion == "rg8snorm") { - *outEnum = wgpu::TextureFormat::RG8Snorm; - } else if (inUnion == "rg8uint") { - *outEnum = wgpu::TextureFormat::RG8Uint; - } else if (inUnion == "rg8sint") { - *outEnum = wgpu::TextureFormat::RG8Sint; - } else if (inUnion == "r32uint") { - *outEnum = wgpu::TextureFormat::R32Uint; - } else if (inUnion == "r32sint") { - *outEnum = wgpu::TextureFormat::R32Sint; - } else if (inUnion == "r32float") { - *outEnum = wgpu::TextureFormat::R32Float; - } else if (inUnion == "rg16uint") { - *outEnum = wgpu::TextureFormat::RG16Uint; - } else if (inUnion == "rg16sint") { - *outEnum = wgpu::TextureFormat::RG16Sint; - } else if (inUnion == "rg16float") { - *outEnum = wgpu::TextureFormat::RG16Float; - } else if (inUnion == "rgba8unorm") { - *outEnum = wgpu::TextureFormat::RGBA8Unorm; - } else if (inUnion == "rgba8unorm-srgb") { - *outEnum = wgpu::TextureFormat::RGBA8UnormSrgb; - } else if (inUnion == "rgba8snorm") { - *outEnum = wgpu::TextureFormat::RGBA8Snorm; - } else if (inUnion == "rgba8uint") { - *outEnum = wgpu::TextureFormat::RGBA8Uint; - } else if (inUnion == "rgba8sint") { - *outEnum = wgpu::TextureFormat::RGBA8Sint; - } else if (inUnion == "bgra8unorm") { - *outEnum = wgpu::TextureFormat::BGRA8Unorm; - } else if (inUnion == "bgra8unorm-srgb") { - *outEnum = wgpu::TextureFormat::BGRA8UnormSrgb; - } else if (inUnion == "rgb9e5ufloat") { - *outEnum = wgpu::TextureFormat::RGB9E5Ufloat; - } else if (inUnion == "rgb10a2uint") { - *outEnum = wgpu::TextureFormat::RGB10A2Uint; - } else if (inUnion == "rgb10a2unorm") { - *outEnum = wgpu::TextureFormat::RGB10A2Unorm; - } else if (inUnion == "rg11b10ufloat") { - *outEnum = wgpu::TextureFormat::RG11B10Ufloat; - } else if (inUnion == "rg32uint") { - *outEnum = wgpu::TextureFormat::RG32Uint; - } else if (inUnion == "rg32sint") { - *outEnum = wgpu::TextureFormat::RG32Sint; - } else if (inUnion == "rg32float") { - *outEnum = wgpu::TextureFormat::RG32Float; - } else if (inUnion == "rgba16uint") { - *outEnum = wgpu::TextureFormat::RGBA16Uint; - } else if (inUnion == "rgba16sint") { - *outEnum = wgpu::TextureFormat::RGBA16Sint; - } else if (inUnion == "rgba16float") { - *outEnum = wgpu::TextureFormat::RGBA16Float; - } else if (inUnion == "rgba32uint") { - *outEnum = wgpu::TextureFormat::RGBA32Uint; - } else if (inUnion == "rgba32sint") { - *outEnum = wgpu::TextureFormat::RGBA32Sint; - } else if (inUnion == "rgba32float") { - *outEnum = wgpu::TextureFormat::RGBA32Float; - } else if (inUnion == "stencil8") { - *outEnum = wgpu::TextureFormat::Stencil8; - } else if (inUnion == "depth16unorm") { - *outEnum = wgpu::TextureFormat::Depth16Unorm; - } else if (inUnion == "depth24plus") { - *outEnum = wgpu::TextureFormat::Depth24Plus; - } else if (inUnion == "depth24plus-stencil8") { - *outEnum = wgpu::TextureFormat::Depth24PlusStencil8; - } else if (inUnion == "depth32float") { - *outEnum = wgpu::TextureFormat::Depth32Float; - } else if (inUnion == "bc1-rgba-unorm") { - *outEnum = wgpu::TextureFormat::BC1RGBAUnorm; - } else if (inUnion == "bc1-rgba-unorm-srgb") { - *outEnum = wgpu::TextureFormat::BC1RGBAUnormSrgb; - } else if (inUnion == "bc2-rgba-unorm") { - *outEnum = wgpu::TextureFormat::BC2RGBAUnorm; - } else if (inUnion == "bc2-rgba-unorm-srgb") { - *outEnum = wgpu::TextureFormat::BC2RGBAUnormSrgb; - } else if (inUnion == "bc3-rgba-unorm") { - *outEnum = wgpu::TextureFormat::BC3RGBAUnorm; - } else if (inUnion == "bc3-rgba-unorm-srgb") { - *outEnum = wgpu::TextureFormat::BC3RGBAUnormSrgb; - } else if (inUnion == "bc4-r-unorm") { - *outEnum = wgpu::TextureFormat::BC4RUnorm; - } else if (inUnion == "bc4-r-snorm") { - *outEnum = wgpu::TextureFormat::BC4RSnorm; - } else if (inUnion == "bc5-rg-unorm") { - *outEnum = wgpu::TextureFormat::BC5RGUnorm; - } else if (inUnion == "bc5-rg-snorm") { - *outEnum = wgpu::TextureFormat::BC5RGSnorm; - } else if (inUnion == "bc6h-rgb-ufloat") { - *outEnum = wgpu::TextureFormat::BC6HRGBUfloat; - } else if (inUnion == "bc6h-rgb-float") { - *outEnum = wgpu::TextureFormat::BC6HRGBFloat; - } else if (inUnion == "bc7-rgba-unorm") { - *outEnum = wgpu::TextureFormat::BC7RGBAUnorm; - } else if (inUnion == "bc7-rgba-unorm-srgb") { - *outEnum = wgpu::TextureFormat::BC7RGBAUnormSrgb; - } else if (inUnion == "etc2-rgb8unorm") { - *outEnum = wgpu::TextureFormat::ETC2RGB8Unorm; - } else if (inUnion == "etc2-rgb8unorm-srgb") { - *outEnum = wgpu::TextureFormat::ETC2RGB8UnormSrgb; - } else if (inUnion == "etc2-rgb8a1unorm") { - *outEnum = wgpu::TextureFormat::ETC2RGB8A1Unorm; - } else if (inUnion == "etc2-rgb8a1unorm-srgb") { - *outEnum = wgpu::TextureFormat::ETC2RGB8A1UnormSrgb; - } else if (inUnion == "etc2-rgba8unorm") { - *outEnum = wgpu::TextureFormat::ETC2RGBA8Unorm; - } else if (inUnion == "etc2-rgba8unorm-srgb") { - *outEnum = wgpu::TextureFormat::ETC2RGBA8UnormSrgb; - } else if (inUnion == "eac-r11unorm") { - *outEnum = wgpu::TextureFormat::EACR11Unorm; - } else if (inUnion == "eac-r11snorm") { - *outEnum = wgpu::TextureFormat::EACR11Snorm; - } else if (inUnion == "eac-rg11unorm") { - *outEnum = wgpu::TextureFormat::EACRG11Unorm; - } else if (inUnion == "eac-rg11snorm") { - *outEnum = wgpu::TextureFormat::EACRG11Snorm; - } else if (inUnion == "astc-4x4-unorm") { - *outEnum = wgpu::TextureFormat::ASTC4x4Unorm; - } else if (inUnion == "astc-4x4-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC4x4UnormSrgb; - } else if (inUnion == "astc-5x4-unorm") { - *outEnum = wgpu::TextureFormat::ASTC5x4Unorm; - } else if (inUnion == "astc-5x4-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC5x4UnormSrgb; - } else if (inUnion == "astc-5x5-unorm") { - *outEnum = wgpu::TextureFormat::ASTC5x5Unorm; - } else if (inUnion == "astc-5x5-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC5x5UnormSrgb; - } else if (inUnion == "astc-6x5-unorm") { - *outEnum = wgpu::TextureFormat::ASTC6x5Unorm; - } else if (inUnion == "astc-6x5-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC6x5UnormSrgb; - } else if (inUnion == "astc-6x6-unorm") { - *outEnum = wgpu::TextureFormat::ASTC6x6Unorm; - } else if (inUnion == "astc-6x6-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC6x6UnormSrgb; - } else if (inUnion == "astc-8x5-unorm") { - *outEnum = wgpu::TextureFormat::ASTC8x5Unorm; - } else if (inUnion == "astc-8x5-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC8x5UnormSrgb; - } else if (inUnion == "astc-8x6-unorm") { - *outEnum = wgpu::TextureFormat::ASTC8x6Unorm; - } else if (inUnion == "astc-8x6-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC8x6UnormSrgb; - } else if (inUnion == "astc-8x8-unorm") { - *outEnum = wgpu::TextureFormat::ASTC8x8Unorm; - } else if (inUnion == "astc-8x8-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC8x8UnormSrgb; - } else if (inUnion == "astc-10x5-unorm") { - *outEnum = wgpu::TextureFormat::ASTC10x5Unorm; - } else if (inUnion == "astc-10x5-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC10x5UnormSrgb; - } else if (inUnion == "astc-10x6-unorm") { - *outEnum = wgpu::TextureFormat::ASTC10x6Unorm; - } else if (inUnion == "astc-10x6-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC10x6UnormSrgb; - } else if (inUnion == "astc-10x8-unorm") { - *outEnum = wgpu::TextureFormat::ASTC10x8Unorm; - } else if (inUnion == "astc-10x8-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC10x8UnormSrgb; - } else if (inUnion == "astc-10x10-unorm") { - *outEnum = wgpu::TextureFormat::ASTC10x10Unorm; - } else if (inUnion == "astc-10x10-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC10x10UnormSrgb; - } else if (inUnion == "astc-12x10-unorm") { - *outEnum = wgpu::TextureFormat::ASTC12x10Unorm; - } else if (inUnion == "astc-12x10-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC12x10UnormSrgb; - } else if (inUnion == "astc-12x12-unorm") { - *outEnum = wgpu::TextureFormat::ASTC12x12Unorm; - } else if (inUnion == "astc-12x12-unorm-srgb") { - *outEnum = wgpu::TextureFormat::ASTC12x12UnormSrgb; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::TextureFormat inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::TextureFormat::Depth32FloatStencil8: - *outUnion = "depth32float-stencil8"; - break; - case wgpu::TextureFormat::R8Unorm: - *outUnion = "r8unorm"; - break; - case wgpu::TextureFormat::R8Snorm: - *outUnion = "r8snorm"; - break; - case wgpu::TextureFormat::R8Uint: - *outUnion = "r8uint"; - break; - case wgpu::TextureFormat::R8Sint: - *outUnion = "r8sint"; - break; - case wgpu::TextureFormat::R16Uint: - *outUnion = "r16uint"; - break; - case wgpu::TextureFormat::R16Sint: - *outUnion = "r16sint"; - break; - case wgpu::TextureFormat::R16Float: - *outUnion = "r16float"; - break; - case wgpu::TextureFormat::RG8Unorm: - *outUnion = "rg8unorm"; - break; - case wgpu::TextureFormat::RG8Snorm: - *outUnion = "rg8snorm"; - break; - case wgpu::TextureFormat::RG8Uint: - *outUnion = "rg8uint"; - break; - case wgpu::TextureFormat::RG8Sint: - *outUnion = "rg8sint"; - break; - case wgpu::TextureFormat::R32Uint: - *outUnion = "r32uint"; - break; - case wgpu::TextureFormat::R32Sint: - *outUnion = "r32sint"; - break; - case wgpu::TextureFormat::R32Float: - *outUnion = "r32float"; - break; - case wgpu::TextureFormat::RG16Uint: - *outUnion = "rg16uint"; - break; - case wgpu::TextureFormat::RG16Sint: - *outUnion = "rg16sint"; - break; - case wgpu::TextureFormat::RG16Float: - *outUnion = "rg16float"; - break; - case wgpu::TextureFormat::RGBA8Unorm: - *outUnion = "rgba8unorm"; - break; - case wgpu::TextureFormat::RGBA8UnormSrgb: - *outUnion = "rgba8unorm-srgb"; - break; - case wgpu::TextureFormat::RGBA8Snorm: - *outUnion = "rgba8snorm"; - break; - case wgpu::TextureFormat::RGBA8Uint: - *outUnion = "rgba8uint"; - break; - case wgpu::TextureFormat::RGBA8Sint: - *outUnion = "rgba8sint"; - break; - case wgpu::TextureFormat::BGRA8Unorm: - *outUnion = "bgra8unorm"; - break; - case wgpu::TextureFormat::BGRA8UnormSrgb: - *outUnion = "bgra8unorm-srgb"; - break; - case wgpu::TextureFormat::RGB9E5Ufloat: - *outUnion = "rgb9e5ufloat"; - break; - case wgpu::TextureFormat::RGB10A2Uint: - *outUnion = "rgb10a2uint"; - break; - case wgpu::TextureFormat::RGB10A2Unorm: - *outUnion = "rgb10a2unorm"; - break; - case wgpu::TextureFormat::RG11B10Ufloat: - *outUnion = "rg11b10ufloat"; - break; - case wgpu::TextureFormat::RG32Uint: - *outUnion = "rg32uint"; - break; - case wgpu::TextureFormat::RG32Sint: - *outUnion = "rg32sint"; - break; - case wgpu::TextureFormat::RG32Float: - *outUnion = "rg32float"; - break; - case wgpu::TextureFormat::RGBA16Uint: - *outUnion = "rgba16uint"; - break; - case wgpu::TextureFormat::RGBA16Sint: - *outUnion = "rgba16sint"; - break; - case wgpu::TextureFormat::RGBA16Float: - *outUnion = "rgba16float"; - break; - case wgpu::TextureFormat::RGBA32Uint: - *outUnion = "rgba32uint"; - break; - case wgpu::TextureFormat::RGBA32Sint: - *outUnion = "rgba32sint"; - break; - case wgpu::TextureFormat::RGBA32Float: - *outUnion = "rgba32float"; - break; - case wgpu::TextureFormat::Stencil8: - *outUnion = "stencil8"; - break; - case wgpu::TextureFormat::Depth16Unorm: - *outUnion = "depth16unorm"; - break; - case wgpu::TextureFormat::Depth24Plus: - *outUnion = "depth24plus"; - break; - case wgpu::TextureFormat::Depth24PlusStencil8: - *outUnion = "depth24plus-stencil8"; - break; - case wgpu::TextureFormat::Depth32Float: - *outUnion = "depth32float"; - break; - case wgpu::TextureFormat::BC1RGBAUnorm: - *outUnion = "bc1-rgba-unorm"; - break; - case wgpu::TextureFormat::BC1RGBAUnormSrgb: - *outUnion = "bc1-rgba-unorm-srgb"; - break; - case wgpu::TextureFormat::BC2RGBAUnorm: - *outUnion = "bc2-rgba-unorm"; - break; - case wgpu::TextureFormat::BC2RGBAUnormSrgb: - *outUnion = "bc2-rgba-unorm-srgb"; - break; - case wgpu::TextureFormat::BC3RGBAUnorm: - *outUnion = "bc3-rgba-unorm"; - break; - case wgpu::TextureFormat::BC3RGBAUnormSrgb: - *outUnion = "bc3-rgba-unorm-srgb"; - break; - case wgpu::TextureFormat::BC4RUnorm: - *outUnion = "bc4-r-unorm"; - break; - case wgpu::TextureFormat::BC4RSnorm: - *outUnion = "bc4-r-snorm"; - break; - case wgpu::TextureFormat::BC5RGUnorm: - *outUnion = "bc5-rg-unorm"; - break; - case wgpu::TextureFormat::BC5RGSnorm: - *outUnion = "bc5-rg-snorm"; - break; - case wgpu::TextureFormat::BC6HRGBUfloat: - *outUnion = "bc6h-rgb-ufloat"; - break; - case wgpu::TextureFormat::BC6HRGBFloat: - *outUnion = "bc6h-rgb-float"; - break; - case wgpu::TextureFormat::BC7RGBAUnorm: - *outUnion = "bc7-rgba-unorm"; - break; - case wgpu::TextureFormat::BC7RGBAUnormSrgb: - *outUnion = "bc7-rgba-unorm-srgb"; - break; - case wgpu::TextureFormat::ETC2RGB8Unorm: - *outUnion = "etc2-rgb8unorm"; - break; - case wgpu::TextureFormat::ETC2RGB8UnormSrgb: - *outUnion = "etc2-rgb8unorm-srgb"; - break; - case wgpu::TextureFormat::ETC2RGB8A1Unorm: - *outUnion = "etc2-rgb8a1unorm"; - break; - case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: - *outUnion = "etc2-rgb8a1unorm-srgb"; - break; - case wgpu::TextureFormat::ETC2RGBA8Unorm: - *outUnion = "etc2-rgba8unorm"; - break; - case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: - *outUnion = "etc2-rgba8unorm-srgb"; - break; - case wgpu::TextureFormat::EACR11Unorm: - *outUnion = "eac-r11unorm"; - break; - case wgpu::TextureFormat::EACR11Snorm: - *outUnion = "eac-r11snorm"; - break; - case wgpu::TextureFormat::EACRG11Unorm: - *outUnion = "eac-rg11unorm"; - break; - case wgpu::TextureFormat::EACRG11Snorm: - *outUnion = "eac-rg11snorm"; - break; - case wgpu::TextureFormat::ASTC4x4Unorm: - *outUnion = "astc-4x4-unorm"; - break; - case wgpu::TextureFormat::ASTC4x4UnormSrgb: - *outUnion = "astc-4x4-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC5x4Unorm: - *outUnion = "astc-5x4-unorm"; - break; - case wgpu::TextureFormat::ASTC5x4UnormSrgb: - *outUnion = "astc-5x4-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC5x5Unorm: - *outUnion = "astc-5x5-unorm"; - break; - case wgpu::TextureFormat::ASTC5x5UnormSrgb: - *outUnion = "astc-5x5-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC6x5Unorm: - *outUnion = "astc-6x5-unorm"; - break; - case wgpu::TextureFormat::ASTC6x5UnormSrgb: - *outUnion = "astc-6x5-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC6x6Unorm: - *outUnion = "astc-6x6-unorm"; - break; - case wgpu::TextureFormat::ASTC6x6UnormSrgb: - *outUnion = "astc-6x6-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC8x5Unorm: - *outUnion = "astc-8x5-unorm"; - break; - case wgpu::TextureFormat::ASTC8x5UnormSrgb: - *outUnion = "astc-8x5-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC8x6Unorm: - *outUnion = "astc-8x6-unorm"; - break; - case wgpu::TextureFormat::ASTC8x6UnormSrgb: - *outUnion = "astc-8x6-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC8x8Unorm: - *outUnion = "astc-8x8-unorm"; - break; - case wgpu::TextureFormat::ASTC8x8UnormSrgb: - *outUnion = "astc-8x8-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC10x5Unorm: - *outUnion = "astc-10x5-unorm"; - break; - case wgpu::TextureFormat::ASTC10x5UnormSrgb: - *outUnion = "astc-10x5-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC10x6Unorm: - *outUnion = "astc-10x6-unorm"; - break; - case wgpu::TextureFormat::ASTC10x6UnormSrgb: - *outUnion = "astc-10x6-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC10x8Unorm: - *outUnion = "astc-10x8-unorm"; - break; - case wgpu::TextureFormat::ASTC10x8UnormSrgb: - *outUnion = "astc-10x8-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC10x10Unorm: - *outUnion = "astc-10x10-unorm"; - break; - case wgpu::TextureFormat::ASTC10x10UnormSrgb: - *outUnion = "astc-10x10-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC12x10Unorm: - *outUnion = "astc-12x10-unorm"; - break; - case wgpu::TextureFormat::ASTC12x10UnormSrgb: - *outUnion = "astc-12x10-unorm-srgb"; - break; - case wgpu::TextureFormat::ASTC12x12Unorm: - *outUnion = "astc-12x12-unorm"; - break; - case wgpu::TextureFormat::ASTC12x12UnormSrgb: - *outUnion = "astc-12x12-unorm-srgb"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::TextureSampleType *outEnum) { - if (inUnion == "float") { - *outEnum = wgpu::TextureSampleType::Float; - } else if (inUnion == "unfilterable-float") { - *outEnum = wgpu::TextureSampleType::UnfilterableFloat; - } else if (inUnion == "depth") { - *outEnum = wgpu::TextureSampleType::Depth; - } else if (inUnion == "sint") { - *outEnum = wgpu::TextureSampleType::Sint; - } else if (inUnion == "uint") { - *outEnum = wgpu::TextureSampleType::Uint; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::TextureSampleType inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::TextureSampleType::Float: - *outUnion = "float"; - break; - case wgpu::TextureSampleType::UnfilterableFloat: - *outUnion = "unfilterable-float"; - break; - case wgpu::TextureSampleType::Depth: - *outUnion = "depth"; - break; - case wgpu::TextureSampleType::Sint: - *outUnion = "sint"; - break; - case wgpu::TextureSampleType::Uint: - *outUnion = "uint"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::TextureViewDimension *outEnum) { - if (inUnion == "1d") { - *outEnum = wgpu::TextureViewDimension::e1D; - } else if (inUnion == "2d") { - *outEnum = wgpu::TextureViewDimension::e2D; - } else if (inUnion == "3d") { - *outEnum = wgpu::TextureViewDimension::e3D; - } else if (inUnion == "2d-array") { - *outEnum = wgpu::TextureViewDimension::e2DArray; - } else if (inUnion == "cube") { - *outEnum = wgpu::TextureViewDimension::Cube; - } else if (inUnion == "cube-array") { - *outEnum = wgpu::TextureViewDimension::CubeArray; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::TextureViewDimension inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::TextureViewDimension::e1D: - *outUnion = "1d"; - break; - case wgpu::TextureViewDimension::e2D: - *outUnion = "2d"; - break; - case wgpu::TextureViewDimension::e3D: - *outUnion = "3d"; - break; - case wgpu::TextureViewDimension::e2DArray: - *outUnion = "2d-array"; - break; - case wgpu::TextureViewDimension::Cube: - *outUnion = "cube"; - break; - case wgpu::TextureViewDimension::CubeArray: - *outUnion = "cube-array"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::VertexFormat *outEnum) { - if (inUnion == "uint32") { - *outEnum = wgpu::VertexFormat::Uint32; - } else if (inUnion == "uint8x2") { - *outEnum = wgpu::VertexFormat::Uint8x2; - } else if (inUnion == "uint8x4") { - *outEnum = wgpu::VertexFormat::Uint8x4; - } else if (inUnion == "sint8x2") { - *outEnum = wgpu::VertexFormat::Sint8x2; - } else if (inUnion == "sint8x4") { - *outEnum = wgpu::VertexFormat::Sint8x4; - } else if (inUnion == "unorm8x2") { - *outEnum = wgpu::VertexFormat::Unorm8x2; - } else if (inUnion == "unorm8x4") { - *outEnum = wgpu::VertexFormat::Unorm8x4; - } else if (inUnion == "snorm8x2") { - *outEnum = wgpu::VertexFormat::Snorm8x2; - } else if (inUnion == "snorm8x4") { - *outEnum = wgpu::VertexFormat::Snorm8x4; - } else if (inUnion == "uint16x2") { - *outEnum = wgpu::VertexFormat::Uint16x2; - } else if (inUnion == "uint16x4") { - *outEnum = wgpu::VertexFormat::Uint16x4; - } else if (inUnion == "sint16x2") { - *outEnum = wgpu::VertexFormat::Sint16x2; - } else if (inUnion == "sint16x4") { - *outEnum = wgpu::VertexFormat::Sint16x4; - } else if (inUnion == "unorm16x2") { - *outEnum = wgpu::VertexFormat::Unorm16x2; - } else if (inUnion == "unorm16x4") { - *outEnum = wgpu::VertexFormat::Unorm16x4; - } else if (inUnion == "snorm16x2") { - *outEnum = wgpu::VertexFormat::Snorm16x2; - } else if (inUnion == "snorm16x4") { - *outEnum = wgpu::VertexFormat::Snorm16x4; - } else if (inUnion == "float16x2") { - *outEnum = wgpu::VertexFormat::Float16x2; - } else if (inUnion == "float16x4") { - *outEnum = wgpu::VertexFormat::Float16x4; - } else if (inUnion == "float32") { - *outEnum = wgpu::VertexFormat::Float32; - } else if (inUnion == "float32x2") { - *outEnum = wgpu::VertexFormat::Float32x2; - } else if (inUnion == "float32x3") { - *outEnum = wgpu::VertexFormat::Float32x3; - } else if (inUnion == "float32x4") { - *outEnum = wgpu::VertexFormat::Float32x4; - } else if (inUnion == "uint32x2") { - *outEnum = wgpu::VertexFormat::Uint32x2; - } else if (inUnion == "uint32x3") { - *outEnum = wgpu::VertexFormat::Uint32x3; - } else if (inUnion == "uint32x4") { - *outEnum = wgpu::VertexFormat::Uint32x4; - } else if (inUnion == "sint32") { - *outEnum = wgpu::VertexFormat::Sint32; - } else if (inUnion == "sint32x2") { - *outEnum = wgpu::VertexFormat::Sint32x2; - } else if (inUnion == "sint32x3") { - *outEnum = wgpu::VertexFormat::Sint32x3; - } else if (inUnion == "sint32x4") { - *outEnum = wgpu::VertexFormat::Sint32x4; - } else if (inUnion == "unorm10-10-10-2") { - *outEnum = wgpu::VertexFormat::Unorm10_10_10_2; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::VertexFormat inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::VertexFormat::Uint32: - *outUnion = "uint32"; - break; - case wgpu::VertexFormat::Uint8x2: - *outUnion = "uint8x2"; - break; - case wgpu::VertexFormat::Uint8x4: - *outUnion = "uint8x4"; - break; - case wgpu::VertexFormat::Sint8x2: - *outUnion = "sint8x2"; - break; - case wgpu::VertexFormat::Sint8x4: - *outUnion = "sint8x4"; - break; - case wgpu::VertexFormat::Unorm8x2: - *outUnion = "unorm8x2"; - break; - case wgpu::VertexFormat::Unorm8x4: - *outUnion = "unorm8x4"; - break; - case wgpu::VertexFormat::Snorm8x2: - *outUnion = "snorm8x2"; - break; - case wgpu::VertexFormat::Snorm8x4: - *outUnion = "snorm8x4"; - break; - case wgpu::VertexFormat::Uint16x2: - *outUnion = "uint16x2"; - break; - case wgpu::VertexFormat::Uint16x4: - *outUnion = "uint16x4"; - break; - case wgpu::VertexFormat::Sint16x2: - *outUnion = "sint16x2"; - break; - case wgpu::VertexFormat::Sint16x4: - *outUnion = "sint16x4"; - break; - case wgpu::VertexFormat::Unorm16x2: - *outUnion = "unorm16x2"; - break; - case wgpu::VertexFormat::Unorm16x4: - *outUnion = "unorm16x4"; - break; - case wgpu::VertexFormat::Snorm16x2: - *outUnion = "snorm16x2"; - break; - case wgpu::VertexFormat::Snorm16x4: - *outUnion = "snorm16x4"; - break; - case wgpu::VertexFormat::Float16x2: - *outUnion = "float16x2"; - break; - case wgpu::VertexFormat::Float16x4: - *outUnion = "float16x4"; - break; - case wgpu::VertexFormat::Float32: - *outUnion = "float32"; - break; - case wgpu::VertexFormat::Float32x2: - *outUnion = "float32x2"; - break; - case wgpu::VertexFormat::Float32x3: - *outUnion = "float32x3"; - break; - case wgpu::VertexFormat::Float32x4: - *outUnion = "float32x4"; - break; - case wgpu::VertexFormat::Uint32x2: - *outUnion = "uint32x2"; - break; - case wgpu::VertexFormat::Uint32x3: - *outUnion = "uint32x3"; - break; - case wgpu::VertexFormat::Uint32x4: - *outUnion = "uint32x4"; - break; - case wgpu::VertexFormat::Sint32: - *outUnion = "sint32"; - break; - case wgpu::VertexFormat::Sint32x2: - *outUnion = "sint32x2"; - break; - case wgpu::VertexFormat::Sint32x3: - *outUnion = "sint32x3"; - break; - case wgpu::VertexFormat::Sint32x4: - *outUnion = "sint32x4"; - break; - case wgpu::VertexFormat::Unorm10_10_10_2: - *outUnion = "unorm10-10-10-2"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - wgpu::VertexStepMode *outEnum) { - if (inUnion == "vertex") { - *outEnum = wgpu::VertexStepMode::Vertex; - } else if (inUnion == "instance") { - *outEnum = wgpu::VertexStepMode::Instance; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(wgpu::VertexStepMode inEnum, - std::string *outUnion) { - switch (inEnum) { - case wgpu::VertexStepMode::Vertex: - *outUnion = "vertex"; - break; - case wgpu::VertexStepMode::Instance: - *outUnion = "instance"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - rnwgpu::PredefinedColorSpace *outEnum) { - if (inUnion == "display-p3") { - *outEnum = rnwgpu::PredefinedColorSpace::DisplayP3; - } else if (inUnion == "srgb") { - *outEnum = rnwgpu::PredefinedColorSpace::Srgb; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(rnwgpu::PredefinedColorSpace inEnum, - std::string *outUnion) { - switch (inEnum) { - case rnwgpu::PredefinedColorSpace::DisplayP3: - *outUnion = "display-p3"; - break; - case rnwgpu::PredefinedColorSpace::Srgb: - *outUnion = "srgb"; - break; - default: - throw invalidEnum(inEnum); - } -} - -inline void convertJSUnionToEnum(const std::string &inUnion, - rnwgpu::PremultiplyAlpha *outEnum) { - if (inUnion == "none") { - *outEnum = rnwgpu::PremultiplyAlpha::None; - } else if (inUnion == "default") { - *outEnum = rnwgpu::PremultiplyAlpha::Default; - } else if (inUnion == "premultiply") { - *outEnum = rnwgpu::PremultiplyAlpha::Premultiply; - } else { - throw invalidUnion(inUnion); - } -} - -inline void convertEnumToJSUnion(rnwgpu::PremultiplyAlpha inEnum, - std::string *outUnion) { - switch (inEnum) { - case rnwgpu::PremultiplyAlpha::None: - *outUnion = "none"; - break; - case rnwgpu::PremultiplyAlpha::Default: - *outUnion = "default"; - break; - case rnwgpu::PremultiplyAlpha::Premultiply: - *outUnion = "premultiply"; - break; - default: - throw invalidEnum(inEnum); - } -} - -} // namespace EnumMapper -} // namespace rnwgpu diff --git a/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.cpp b/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.cpp deleted file mode 100644 index 9353357184..0000000000 --- a/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "AsyncTaskHandle.h" - -#include -#include -#include - -#include - -#include "jsi/Promise.h" - -#include "RuntimeContext.h" - -namespace rnwgpu::async { - -using Action = std::function; - -struct AsyncTaskHandle::State - : public std::enable_shared_from_this { - State(std::shared_ptr context, bool keepPumping) - : context(std::move(context)), keepPumping(keepPumping) {} - - void settle(Action action); - void attachPromise(const std::shared_ptr &promise); - void schedule(Action action); - - ResolveFunction createResolveFunction(); - RejectFunction createRejectFunction(); - - std::shared_ptr currentPromise(); - - std::mutex mutex; - std::shared_ptr context; - bool keepPumping; - std::shared_ptr promise; - std::optional pendingAction; - bool settled = false; - std::shared_ptr keepAlive; -}; - -// MARK: - State helpers - -void AsyncTaskHandle::State::settle(Action action) { - std::optional actionToSchedule; - - { - std::lock_guard lock(mutex); - if (settled) { - return; - } - settled = true; - - if (promise) { - actionToSchedule = std::move(action); - } else { - pendingAction = std::move(action); - } - } - - if (actionToSchedule.has_value()) { - schedule(std::move(*actionToSchedule)); - } -} - -void AsyncTaskHandle::State::attachPromise( - const std::shared_ptr &newPromise) { - std::optional actionToSchedule; - { - std::lock_guard lock(mutex); - promise = newPromise; - keepAlive = shared_from_this(); - if (pendingAction.has_value()) { - actionToSchedule = std::move(pendingAction); - pendingAction.reset(); - } - } - - if (actionToSchedule.has_value()) { - schedule(std::move(*actionToSchedule)); - } -} - -void AsyncTaskHandle::State::schedule(Action action) { - auto promiseRef = currentPromise(); - if (!promiseRef) { - return; - } - - if (!context) { - // No context (shouldn't happen): best-effort inline settle. - action(promiseRef->runtime, *promiseRef); - std::lock_guard lock(mutex); - keepAlive.reset(); - return; - } - - auto self = shared_from_this(); - - if (!keepPumping) { - // Spontaneous task (e.g. device.lost): not driven by the ProcessEvents - // pump. Settle on the owning runtime's JS thread via its CallInvoker, which - // is wired only for the main JS runtime. A device created on a worklet - // runtime has no invoker, so its device.lost is dropped (best-effort; see - // the Threading model). invokeAsync runs the closure on the main JS thread, - // where promiseRef->runtime lives for a main-runtime device. - auto invoker = context->callInvoker(); - if (invoker) { - invoker->invokeAsync( - [self, action = std::move(action), promiseRef]() mutable { - action(promiseRef->runtime, *promiseRef); - std::lock_guard lock(self->mutex); - self->keepAlive.reset(); - }); - } else { - std::lock_guard lock(mutex); - keepAlive.reset(); - } - return; - } - - // Pumping task (request/response op). The resolve/reject callback may fire on - // a thread that is NOT the owning runtime's thread: with a shared - // wgpu::Instance, another runtime's ProcessEvents() pump can consume this - // Dawn event. Touching the Promise's runtime off-thread would corrupt Hermes. - // So we deposit the actual settle (the only JSI-touching work) into the - // owning context's mailbox; the context drains it on its own thread during - // its next tick. The deposited closure captures only C++ state and runs no - // JSI until drained, so depositing from any thread is safe. - context->postSettle([self, action = std::move(action), promiseRef]() mutable { - action(promiseRef->runtime, *promiseRef); - if (self->context) { - self->context->onTaskSettled(/*keepPumping=*/true); - } - std::lock_guard lock(self->mutex); - self->keepAlive.reset(); - }); -} - -AsyncTaskHandle::ResolveFunction -AsyncTaskHandle::State::createResolveFunction() { - auto weakSelf = std::weak_ptr(shared_from_this()); - return [weakSelf](ValueFactory factory) { - if (auto self = weakSelf.lock()) { - ValueFactory resolvedFactory = - factory ? std::move(factory) : [](jsi::Runtime &runtime) { - return jsi::Value::undefined(); - }; - self->settle( - [factory = std::move(resolvedFactory)]( - jsi::Runtime &runtime, rnwgpu::Promise &promise) mutable { - auto value = factory(runtime); - promise.resolve(std::move(value)); - }); - } - }; -} - -AsyncTaskHandle::RejectFunction AsyncTaskHandle::State::createRejectFunction() { - auto weakSelf = std::weak_ptr(shared_from_this()); - return [weakSelf](std::string reason) { - if (auto self = weakSelf.lock()) { - self->settle([reason = std::move(reason)](jsi::Runtime & /*runtime*/, - rnwgpu::Promise &promise) { - promise.reject(reason); - }); - } - }; -} - -std::shared_ptr AsyncTaskHandle::State::currentPromise() { - std::lock_guard lock(mutex); - return promise; -} - -// MARK: - AsyncTaskHandle - -AsyncTaskHandle::AsyncTaskHandle() = default; - -AsyncTaskHandle::AsyncTaskHandle(std::shared_ptr state) - : _state(std::move(state)) {} - -bool AsyncTaskHandle::valid() const { return _state != nullptr; } - -AsyncTaskHandle -AsyncTaskHandle::create(const std::shared_ptr &context, - bool keepPumping) { - auto state = std::make_shared(context, keepPumping); - state->keepAlive = state; - return AsyncTaskHandle(std::move(state)); -} - -AsyncTaskHandle::ResolveFunction -AsyncTaskHandle::createResolveFunction() const { - if (!_state) { - return [](ValueFactory) {}; - } - return _state->createResolveFunction(); -} - -AsyncTaskHandle::RejectFunction AsyncTaskHandle::createRejectFunction() const { - if (!_state) { - return [](std::string) {}; - } - return _state->createRejectFunction(); -} - -void AsyncTaskHandle::attachPromise( - const std::shared_ptr &promise) const { - if (_state) { - _state->attachPromise(promise); - } -} - -} // namespace rnwgpu::async diff --git a/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.h b/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.h deleted file mode 100644 index fea16c0f63..0000000000 --- a/packages/skia/cpp/rnwgpu/async/AsyncTaskHandle.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include - -namespace rnwgpu { -class Promise; -} - -namespace rnwgpu::async { - -class RuntimeContext; - -/** - * Represents a pending asynchronous WebGPU operation that can be converted into - * a JavaScript Promise. - * - * In the ProcessEvents model the resolve/reject callbacks are invoked on the - * owning runtime's own thread (synchronously from instance.ProcessEvents() - * during the RuntimeContext tick, or synchronously from postTask), so the - * Promise is settled directly without any thread marshalling. - */ -class AsyncTaskHandle { -public: - struct State; - - using ValueFactory = - std::function; - using ResolveFunction = std::function; - using RejectFunction = std::function; - - AsyncTaskHandle(); - - /** - * Internal constructor used by RuntimeContext. - */ - explicit AsyncTaskHandle(std::shared_ptr state); - - bool valid() const; - - ResolveFunction createResolveFunction() const; - RejectFunction createRejectFunction() const; - - void attachPromise(const std::shared_ptr &promise) const; - - static AsyncTaskHandle create(const std::shared_ptr &context, - bool keepPumping); - -private: - std::shared_ptr _state; -}; - -} // namespace rnwgpu::async diff --git a/packages/skia/cpp/rnwgpu/async/RuntimeContext.cpp b/packages/skia/cpp/rnwgpu/async/RuntimeContext.cpp deleted file mode 100644 index ab2de624ab..0000000000 --- a/packages/skia/cpp/rnwgpu/async/RuntimeContext.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "RuntimeContext.h" - -#include -#include -#include - -#include - -#include "AsyncTaskHandle.h" - -namespace rnwgpu::async { - -namespace { -struct RuntimeData { - std::shared_ptr context; -}; - -// The main JS runtime and its CallInvoker, registered once on install. The -// context created for sMainRuntime gets sMainInvoker; spontaneous events -// (device.lost) on a main-runtime device are delivered through it without the -// pump. Worklet runtimes have no invoker (best-effort, see the header doc). -jsi::Runtime *sMainRuntime = nullptr; -std::shared_ptr sMainInvoker; - -// Serializes ProcessEvents() across all runtimes that share a wgpu::Instance. -// Held only across the ProcessEvents call itself, never while running JS / -// mailbox settle-actions, so it cannot deadlock against the per-context mailbox -// mutex. -std::mutex &processEventsMutex() { - static std::mutex mutex; - return mutex; -} -} // namespace - -void RuntimeContext::registerMainRuntime( - jsi::Runtime *runtime, - std::shared_ptr invoker) { - sMainRuntime = runtime; - sMainInvoker = std::move(invoker); -} - -std::shared_ptr -RuntimeContext::mainCallInvoker() { - return sMainInvoker; -} - -RuntimeContext::RuntimeContext(jsi::Runtime &runtime, wgpu::Instance instance) - : _runtime(runtime), _instance(std::move(instance)) {} - -std::shared_ptr RuntimeContext::get(jsi::Runtime &runtime) { - auto data = runtime.getRuntimeData(runtimeDataUUID()); - if (!data) { - return nullptr; - } - return std::static_pointer_cast(data)->context; -} - -std::shared_ptr -RuntimeContext::getOrCreate(jsi::Runtime &runtime, wgpu::Instance instance) { - if (auto existing = get(runtime)) { - return existing; - } - auto context = std::make_shared(runtime, std::move(instance)); - // Only the main JS runtime's context carries the CallInvoker; it is used to - // deliver spontaneous events (device.lost) without the pump. - if (&runtime == sMainRuntime) { - context->_callInvoker = sMainInvoker; - } - auto data = std::make_shared(); - data->context = context; - runtime.setRuntimeData(runtimeDataUUID(), data); - return context; -} - -AsyncTaskHandle RuntimeContext::postTask(const TaskCallback &callback, - bool keepPumping) { - auto handle = AsyncTaskHandle::create(shared_from_this(), keepPumping); - if (!handle.valid()) { - throw std::runtime_error("Failed to create AsyncTaskHandle."); - } - - // Only pumping tasks (request/response ops) drive the ProcessEvents pump. - // Spontaneous tasks (keepPumping == false, e.g. device.lost) never touch the - // pump: they settle via the CallInvoker (see AsyncTaskHandle::State::schedule). - if (keepPumping) { - _pumpTasks.fetch_add(1, std::memory_order_acq_rel); - requestTick(); - } - - auto resolve = handle.createResolveFunction(); - auto reject = handle.createRejectFunction(); - try { - callback(resolve, reject); - } catch (const std::exception &exception) { - reject(exception.what()); - } catch (...) { - reject("Unknown native error in RuntimeContext::postTask."); - } - return handle; -} - -void RuntimeContext::onTaskSettled(bool keepPumping) { - if (keepPumping) { - _pumpTasks.fetch_sub(1, std::memory_order_acq_rel); - } -} - -void RuntimeContext::postSettle(std::function job) { - if (!job) { - return; - } - std::lock_guard lock(_mailboxMutex); - _mailbox.push_back(std::move(job)); -} - -void RuntimeContext::drainMailbox() { - std::vector> jobs; - { - std::lock_guard lock(_mailboxMutex); - jobs.swap(_mailbox); - } - // Run settle-actions on this (the owning) thread, NOT under the ProcessEvents - // mutex, so JS continuations never execute while the pump lock is held. - for (auto &job : jobs) { - job(); - } -} - -void RuntimeContext::requestTick() { - bool expected = false; - if (!_tickScheduled.compare_exchange_strong(expected, true, - std::memory_order_acq_rel)) { - return; - } - - // The pump only ever runs while a request/response op is outstanding, so it - // always schedules as soon as possible (delay 0). postTask and tick both run - // on the owning runtime's thread, so we schedule the next tick directly via - // that runtime's own timer. setTimeout is available on the main RN runtime and - // on worklet runtimes (backed by the worklets EventLoop); setImmediate / - // queueMicrotask are fallbacks. We do NOT use queueMicrotask as the primary - // mechanism: a self-rescheduling microtask never yields the microtask - // checkpoint, starving the runtime's task loop. - auto self = shared_from_this(); - jsi::Runtime &rt = _runtime; - auto tickCallback = jsi::Function::createFromHostFunction( - rt, jsi::PropNameID::forAscii(rt, "RNWGPUAsyncTick"), 0, - [self](jsi::Runtime & /*runtime*/, const jsi::Value & /*thisVal*/, - const jsi::Value * /*args*/, size_t /*count*/) -> jsi::Value { - self->tick(); - return jsi::Value::undefined(); - }); - - auto global = rt.global(); - auto setTimeoutValue = global.getProperty(rt, "setTimeout"); - if (setTimeoutValue.isObject() && - setTimeoutValue.asObject(rt).isFunction(rt)) { - setTimeoutValue.asObject(rt).asFunction(rt).call( - rt, jsi::Value(rt, tickCallback), jsi::Value(0.0)); - return; - } - auto setImmediateValue = global.getProperty(rt, "setImmediate"); - if (setImmediateValue.isObject() && - setImmediateValue.asObject(rt).isFunction(rt)) { - setImmediateValue.asObject(rt).asFunction(rt).call( - rt, jsi::Value(rt, tickCallback)); - return; - } - rt.queueMicrotask(std::move(tickCallback)); -} - -void RuntimeContext::tick() { - _tickScheduled.store(false, std::memory_order_release); - { - // Serialize ProcessEvents across runtimes sharing this instance. Callbacks - // fired here only deposit into mailboxes (postSettle), they do not run JS. - std::lock_guard lock(processEventsMutex()); - _instance.ProcessEvents(); - } - // Settle this runtime's ready promises on this thread, outside the pump lock. - drainMailbox(); - // Keep pumping only while a "pumping" task (active async work) is outstanding. - // Non-pumping tasks (e.g. device.lost) intentionally do NOT keep the pump - // alive: we prioritise battery over catching a device.lost fired while idle. - if (_pumpTasks.load(std::memory_order_acquire) > 0) { - requestTick(); - } -} - -jsi::UUID RuntimeContext::runtimeDataUUID() { - // Fixed, unique key for storing the RuntimeContext in the runtime's - // runtimeData. Must not collide with other runtimeData consumers (e.g. - // react-native-worklets' weakRuntimeUUID). - static const jsi::UUID uuid{0x7b9a3c10, 0x4d2e, 0x4f8a, 0x9c3d, - 0x1f6e5a2b8c40}; - return uuid; -} - -} // namespace rnwgpu::async diff --git a/packages/skia/cpp/rnwgpu/async/RuntimeContext.h b/packages/skia/cpp/rnwgpu/async/RuntimeContext.h deleted file mode 100644 index e7767e5129..0000000000 --- a/packages/skia/cpp/rnwgpu/async/RuntimeContext.h +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -#include "AsyncTaskHandle.h" - -#include "webgpu/webgpu_cpp.h" - -namespace jsi = facebook::jsi; - -namespace facebook::react { -class CallInvoker; -} // namespace facebook::react - -namespace rnwgpu::async { - -/** - * Per-runtime coordinator for asynchronous WebGPU operations. - * - * Each JS runtime that uses WebGPU gets its own RuntimeContext, stored in the - * runtime's runtimeData. Async Dawn operations are registered with - * CallbackMode::AllowProcessEvents and driven to completion by pumping - * `instance.ProcessEvents()` on the runtime's OWN thread via a self- - * rescheduling tick (scheduled through that runtime's setTimeout). Because - * ProcessEvents invokes the Dawn callbacks synchronously on the pumping thread, - * the JS Promise is settled directly on the owning runtime, with no background - * thread and no cross-thread hop. - * - * The pump only runs while at least one "pumping" task is outstanding, so it - * costs nothing when idle and stops cleanly. - * - * Spontaneous events (keepPumping = false): events that may fire at any time, - * independent of any request/response op (today only GPUDevice::getLost, whose - * Dawn callback is registered AllowSpontaneous). These are NOT driven by the - * pump. Instead their settle is marshalled onto the owning runtime's JS thread - * via that runtime's CallInvoker, which is wired only for the MAIN JS runtime - * (callInvoker()). A device created on a worklet runtime has no invoker, so its - * device.lost is best-effort and may never fire. - * - * Shared-instance safety (mailbox): multiple runtimes may share one - * wgpu::Instance. ProcessEvents() drains the whole instance queue and fires - * callbacks on the calling thread, which may NOT be the owning runtime's thread - * for a given promise. So a settled callback never touches JSI inline; it - * deposits a settle-action (a plain C++ closure, no JSI) into the OWNING - * context's thread-safe mailbox via postSettle(), and each context drains its - * own mailbox on its own thread during tick(). ProcessEvents() itself is - * serialized across runtimes by a process-wide mutex, since concurrent - * ProcessEvents on one instance is not guaranteed reentrant. - * - * Threading contract: a RuntimeContext must only be pumped from the runtime it - * was created for. Request/response async entry points (mapAsync, - * onSubmittedWorkDone, popErrorScope, createComputePipelineAsync, - * createRenderPipelineAsync, getCompilationInfo, requestAdapter, - * requestDevice) must NOT use a context captured when the object was created — - * the object may have been boxed across to another runtime. They resolve the - * CALLING runtime's context via getOrCreate(runtime, instance) so the promise - * is settled on the thread it was created on. Spontaneous events (device.lost, - * uncapturederror) remain bound to the device's own context (best-effort, main - * runtime only; see the class doc above). - */ -class RuntimeContext : public std::enable_shared_from_this { -public: - using TaskCallback = - std::function; - - RuntimeContext(jsi::Runtime &runtime, wgpu::Instance instance); - - static std::shared_ptr get(jsi::Runtime &runtime); - static std::shared_ptr getOrCreate(jsi::Runtime &runtime, - wgpu::Instance instance); - - // Register the main JS runtime and its CallInvoker. The RuntimeContext created - // for this runtime gets the invoker (callInvoker() returns it); every other - // runtime's context returns null. Called once from RNSkManager on install. - static void - registerMainRuntime(jsi::Runtime *runtime, - std::shared_ptr invoker); - - // CallInvoker for this runtime's JS thread, or null. Non-null only for the - // main JS runtime; used to deliver spontaneous events (device.lost) without - // the pump. See the class doc. - const std::shared_ptr &callInvoker() const { - return _callInvoker; - } - - // The main JS runtime's CallInvoker (registered on install), or null before - // install. Used by the platform views to apply latched surface attaches from - // the JS thread for contexts that are not actively rendering (see - // SurfaceInfo::applyPendingAttach). - static std::shared_ptr mainCallInvoker(); - - // The wgpu::Instance bound to this runtime. - wgpu::Instance instance() const { return _instance; } - - AsyncTaskHandle postTask(const TaskCallback &callback, - bool keepPumping = true); - - // Deposit a settle-action to run on THIS context's runtime thread. Thread-safe - // (callable from any thread, e.g. another runtime that pumped ProcessEvents). - // The job must not touch JSI until it runs (it runs during drainMailbox on the - // owning thread). - void postSettle(std::function job); - - // Invoked by a drained settle-action when its task settles. Runs on the owning - // runtime's thread. - void onTaskSettled(bool keepPumping); - -private: - static jsi::UUID runtimeDataUUID(); - - void requestTick(); - void tick(); - void drainMailbox(); - - jsi::Runtime &_runtime; - wgpu::Instance _instance; - // Non-null only for the main JS runtime's context (see registerMainRuntime). - std::shared_ptr _callInvoker; - std::atomic _pumpTasks{0}; - std::atomic _tickScheduled{false}; - - std::mutex _mailboxMutex; - std::vector> _mailbox; -}; - -} // namespace rnwgpu::async diff --git a/packages/skia/package.json b/packages/skia/package.json index 598d569afd..b8694e1685 100644 --- a/packages/skia/package.json +++ b/packages/skia/package.json @@ -163,8 +163,7 @@ }, "ios": { "componentProvider": { - "SkiaPictureView": "SkiaPictureView", - "SkiaWebGPUView": "SkiaWebGPUView" + "SkiaPictureView": "SkiaPictureView" } } }, diff --git a/packages/skia/react-native-skia.podspec b/packages/skia/react-native-skia.podspec index 8da3212433..328ff30223 100644 --- a/packages/skia/react-native-skia.podspec +++ b/packages/skia/react-native-skia.podspec @@ -75,8 +75,42 @@ framework_names = ['libskia', 'libsvg', 'libskshaper', 'libskparagraph', 'libskunicode_core', 'libskunicode_libgrapheme', 'libskottie', 'libsksg'] -# Add Dawn library for Graphite builds (contains dawn::native symbols) -framework_names += ['libdawn_combined'] if use_graphite +# Add Dawn library for Graphite builds (contains dawn::native symbols). +# libwebgpu_dawn is the same artifact react-native-webgpu vendors. When +# react-native-webgpu is installed, it provides Dawn for the whole app and +# vendoring the framework here as well would fail CocoaPods' +# duplicate-framework-name check, so Skia only vendors it when alone. The +# skia pod's dawn::native references resolve from webgpu's copy at app link. +webgpu_pkg_dir = resolve_node_package.call('react-native-webgpu', __dir__) +has_webgpu_pkg = !webgpu_pkg_dir.nil? +if use_graphite && has_webgpu_pkg + Pod::UI.puts 'react-native-skia: react-native-webgpu detected, Dawn is provided by its libwebgpu_dawn' + + # Both packages must link the exact same Dawn artifact. Compare the release + # tag this Graphite build was installed with (libs/.dawn-version) against + # the tag react-native-webgpu declares in its package.json `dawn` field. + dawn_marker = File.join(__dir__, 'libs', '.dawn-version') + if File.exist?(dawn_marker) + skia_dawn = File.read(dawn_marker).strip + webgpu_pkg = JSON.parse(File.read(File.join(webgpu_pkg_dir, 'package.json'))) + webgpu_dawn_field = webgpu_pkg['dawn'].to_s + if webgpu_dawn_field.empty? + raise "react-native-skia: the installed react-native-webgpu " \ + "(#{webgpu_pkg['version']}) does not declare a `dawn` field in its " \ + "package.json, so it predates shared-Dawn support and cannot be " \ + "paired with this Graphite build (which links #{skia_dawn}). " \ + "Upgrade react-native-webgpu." + end + webgpu_dawn = "dawn-#{webgpu_dawn_field.tr('/', '-')}" + unless skia_dawn == webgpu_dawn + raise "react-native-skia: Dawn version mismatch. This Graphite build " \ + "links #{skia_dawn} but react-native-webgpu links #{webgpu_dawn}. " \ + "Align the two packages so the app contains exactly one Dawn." + end + Pod::UI.puts "react-native-skia: Dawn versions match (#{skia_dawn})" + end +end +framework_names += ['libwebgpu_dawn'] if use_graphite && !has_webgpu_pkg # Verify that the prebuilt binaries are available (copied in above from the npm # packages, or downloaded by install-skia-graphite for in-repo Graphite builds). @@ -154,8 +188,8 @@ Pod::Spec.new do |s| 'cpp/rnskia/RNMetalLayerColorSpace.h', 'cpp/rnskia/RNDawnWindowContext.h', 'cpp/rnskia/RNDawnWindowContext.cpp', - 'cpp/rnskia/RNImageProvider.h', - 'cpp/rnwgpu/**/*.{h,cpp}' + 'cpp/rnskia/RNDawnInterop.cpp', + 'cpp/rnskia/RNImageProvider.h' ] s.exclude_files = graphite_exclusions unless use_graphite diff --git a/packages/skia/scripts/install-skia-graphite.ts b/packages/skia/scripts/install-skia-graphite.ts index 47ea4e7dbb..e8056fabf0 100644 --- a/packages/skia/scripts/install-skia-graphite.ts +++ b/packages/skia/scripts/install-skia-graphite.ts @@ -46,6 +46,20 @@ const GRAPHITE_CONFIG = { }, } as const; +// Dawn prebuilt binaries. These are the exact artifacts react-native-webgpu +// links; both packages must consume the same Dawn build so that only one Dawn +// copy exists in an app that installs both. The Dawn commit is the one from +// this Skia milestone's DEPS. +const DAWN_CONFIG = { + releaseTag: "dawn-chrome-m150", + baseUrl: + "https://github.com/wcandillon/react-native-webgpu/releases/download", + checksums: { + android: "dee507d4fe66b57f6d33c0dac8cfd1b1263fcd9a8997bfebf936b62341580e60", + apple: "5bacd90c56aa3144d8ba74ac2d769d28b28ebf99c67a4959185c7181d8aeaf31", + }, +} as const; + const SCRIPT_DIR = __dirname; const PACKAGE_ROOT = path.resolve(SCRIPT_DIR, ".."); const REPO_ROOT = path.resolve(PACKAGE_ROOT, "../.."); @@ -134,9 +148,10 @@ const extractTarGz = async ( const downloadAndExtract = async ( assetName: string, destDir: string, - expectedChecksum?: string + expectedChecksum?: string, + urlOverride?: string ): Promise => { - const url = getDownloadUrl(assetName); + const url = urlOverride ?? getDownloadUrl(assetName); const tempFile = path.join(LIBS_DIR, `${assetName}.tmp`); console.log(` Downloading ${assetName}...`); @@ -271,11 +286,70 @@ const downloadAndroidLibs = async (): Promise => { execSync(`mv "${nestedDir}"/* "${destDir}"/`); rmSync(nestedDir, { recursive: true, force: true }); } + + // Dawn comes from the shared dawn-chrome release instead (see + // downloadDawnLibs); drop the bundled copy so it cannot be linked by + // mistake. + rmSync(path.join(destDir, "libdawn_combined.a"), { force: true }); } console.log(` ✓ Android libraries downloaded`); }; +// Download the shared Dawn binaries (same artifacts react-native-webgpu links) +const downloadDawnLibs = async (): Promise => { + console.log(`\n🌅 Downloading Dawn libraries (${DAWN_CONFIG.releaseTag})...`); + + const dawnUrl = (asset: string) => + `${DAWN_CONFIG.baseUrl}/${DAWN_CONFIG.releaseTag}/${asset}`; + + // Android: shared libwebgpu_dawn.so per ABI, next to the Skia static libs + const androidAsset = `dawn-android-${DAWN_CONFIG.releaseTag}.tar.gz`; + const androidTempDir = path.join(LIBS_DIR, "dawn-android-temp"); + await downloadAndExtract( + androidAsset, + androidTempDir, + DAWN_CONFIG.checksums.android, + dawnUrl(androidAsset) + ); + for (const abi of ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]) { + const src = path.join( + androidTempDir, + "dawn-android", + abi, + "libwebgpu_dawn.so" + ); + if (!existsSync(src)) { + throw new Error(`Missing libwebgpu_dawn.so for ${abi} in ${androidAsset}`); + } + fileOps.cp(src, path.join(LIBS_DIR, "android", abi, "libwebgpu_dawn.so")); + } + rmSync(androidTempDir, { recursive: true, force: true }); + + // Apple: one xcframework carrying ios-device, ios-simulator and macos + // slices; the podspec vendors it from both platform dirs + const appleAsset = `dawn-apple-${DAWN_CONFIG.releaseTag}.xcframework.tar.gz`; + const appleTempDir = path.join(LIBS_DIR, "dawn-apple-temp"); + await downloadAndExtract( + appleAsset, + appleTempDir, + DAWN_CONFIG.checksums.apple, + dawnUrl(appleAsset) + ); + const xcframework = path.join(appleTempDir, "dawn-apple.xcframework"); + if (!existsSync(xcframework)) { + throw new Error(`Missing dawn-apple.xcframework in ${appleAsset}`); + } + for (const platform of ["ios", "macos"]) { + const dest = path.join(LIBS_DIR, platform, "libwebgpu_dawn.xcframework"); + fileOps.rm(dest); + fileOps.cp(xcframework, dest); + } + rmSync(appleTempDir, { recursive: true, force: true }); + + console.log(` ✓ Dawn libraries downloaded`); +}; + // Download Apple libraries const downloadAppleLibs = async (): Promise => { console.log(`\n🍎 Downloading Apple Graphite libraries...`); @@ -301,8 +375,9 @@ const downloadAppleLibs = async (): Promise => { const extractedIosDir = path.join(iosTempDir, "ios"); if (existsSync(extractedIosDir)) { - const xcframeworks = readdirSync(extractedIosDir).filter((f) => - f.endsWith(".xcframework") + const xcframeworks = readdirSync(extractedIosDir).filter( + (f) => + f.endsWith(".xcframework") && f !== "libdawn_combined.xcframework" ); for (const xcf of xcframeworks) { fileOps.cp(path.join(extractedIosDir, xcf), path.join(iosDir, xcf)); @@ -321,8 +396,9 @@ const downloadAppleLibs = async (): Promise => { const extractedMacosDir = path.join(macosTempDir, "macos"); if (existsSync(extractedMacosDir)) { - const xcframeworks = readdirSync(extractedMacosDir).filter((f) => - f.endsWith(".xcframework") + const xcframeworks = readdirSync(extractedMacosDir).filter( + (f) => + f.endsWith(".xcframework") && f !== "libdawn_combined.xcframework" ); for (const xcf of xcframeworks) { fileOps.cp(path.join(extractedMacosDir, xcf), path.join(macosDir, xcf)); @@ -354,6 +430,10 @@ const install = async (): Promise => { await downloadAndroidLibs(); await downloadAppleLibs(); + // Download the shared Dawn binaries (must run after the platform libs, which + // clean the destination directories) + await downloadDawnLibs(); + // Download and copy Dawn/WebGPU headers from release tarball await copyDawnHeaders(); @@ -362,6 +442,13 @@ const install = async (): Promise => { writeFileSync(markerFile, GRAPHITE_CONFIG.version, "utf-8"); console.log(` ✓ Wrote Graphite marker file: ${markerFile}`); + // Record the Dawn release tag so the podspec and build.gradle can verify it + // matches the tag react-native-webgpu was built against (both packages must + // link the exact same Dawn artifact). + const dawnMarkerFile = path.join(LIBS_DIR, ".dawn-version"); + writeFileSync(dawnMarkerFile, DAWN_CONFIG.releaseTag, "utf-8"); + console.log(` ✓ Wrote Dawn version marker: ${dawnMarkerFile}`); + console.log( `\n✅ Skia Graphite ${GRAPHITE_CONFIG.version} installed successfully!\n` ); diff --git a/packages/skia/src/mock/__tests__/mock.spec.ts b/packages/skia/src/mock/__tests__/mock.spec.ts index bfa1ddd540..956a3e4b32 100644 --- a/packages/skia/src/mock/__tests__/mock.spec.ts +++ b/packages/skia/src/mock/__tests__/mock.spec.ts @@ -12,7 +12,6 @@ jest.mock("react-native", () => ({ View: jest.fn(), })); jest.mock("../../specs/SkiaPictureViewNativeComponent", () => {}); -jest.mock("../../specs/WebGPUViewNativeComponent", () => {}); jest.mock("../../external/reanimated/index", () => {}); describe("Mocks", () => { diff --git a/packages/skia/src/mock/index.ts b/packages/skia/src/mock/index.ts index 32a7b34565..b7034df29f 100644 --- a/packages/skia/src/mock/index.ts +++ b/packages/skia/src/mock/index.ts @@ -23,7 +23,6 @@ export const Mock = (CanvasKit: CanvasKit) => { ...require("../dom/types"), ...require("../dom/nodes"), Canvas: require("react-native").View, - WebGPUCanvas: require("react-native").View, getPreferredHighBitDepthCanvasFormat: () => "rgba16float", SkiaPictureView: require("react-native").View, JsiSkImage: JsiSkImage, diff --git a/packages/skia/src/renderer/__tests__/e2e/ArrayBuffer.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ArrayBuffer.spec.tsx deleted file mode 100644 index afa4731cd2..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ArrayBuffer.spec.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (ArrayBuffer.spec.ts). Round-trips data -// through GPU buffers (writeBuffer -> copyBufferToBuffer -> mapAsync). WebGPU is -// only available on Graphite (Dawn) builds. -describe("ArrayBuffer", () => { - itRunsWithGraphite("Array Buffer (1)", async () => { - const result = await surface.eval(() => { - return Array.from(new Uint8Array([1.0, 2.0, 3.0, 4.0])); - }); - expect(result.slice(0, 4)).toEqual([1, 2, 3, 4]); - }); - - itRunsWithGraphite("Array Buffer (2)", async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - const data = new Float32Array([1.0, 2.0, 3.0, 4.0]); - const bufferSize = data.byteLength; // 4 32-bit floats - const sourceBuffer = device.createBuffer({ - size: bufferSize, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, - }); - - // Create a buffer for reading - const readBuffer = device.createBuffer({ - size: bufferSize, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - // Write data to the source buffer - device.queue.writeBuffer(sourceBuffer, 0, data); - - // Copy data from source buffer to read buffer - const encoder = device.createCommandEncoder(); - encoder.copyBufferToBuffer(sourceBuffer, 0, readBuffer, 0, bufferSize); - device.queue.submit([encoder.finish()]); - return device.queue.onSubmittedWorkDone().then(() => { - // Map the read buffer for reading - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const readData = new Float32Array(readBuffer.getMappedRange()); - return Array.from(readData); - }); - }); - }); - expect(result).toEqual([1, 2, 3, 4]); - }); - - itRunsWithGraphite("Array Buffer (3)", async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - const data = new Float32Array([1.0, 2.0, 3.0, 4.0]); - const bufferSize = data.byteLength; // 4 32-bit floats - const sourceBuffer = device.createBuffer({ - size: bufferSize, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, - }); - - // Create a buffer for reading - const readBuffer = device.createBuffer({ - size: bufferSize, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - // Write data to the source buffer - device.queue.writeBuffer(sourceBuffer, 0, data); - - // Copy data from source buffer to read buffer - const encoder = device.createCommandEncoder(); - encoder.copyBufferToBuffer(sourceBuffer, 0, readBuffer, 0, bufferSize); - device.queue.submit([encoder.finish()]); - // Map the read buffer for reading - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const readData = new Float32Array(readBuffer.getMappedRange()); - return Array.from(readData); - }); - }); - expect(result).toEqual([1, 2, 3, 4]); - }); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ArrayBufferBounds.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ArrayBufferBounds.spec.tsx deleted file mode 100644 index 1093e6e97b..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ArrayBufferBounds.spec.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// These tests exercise the conversion of JS BufferSources (TypedArrays / -// DataView / raw ArrayBuffer) into the native rnwgpu::ArrayBuffer in -// cpp/rnwgpu/ArrayBuffer.h. -// -// The native `fromJSI` reads `byteOffset` / `byteLength` / `BYTES_PER_ELEMENT` -// directly off the JS object and does `arrayBuffer.data(runtime) + byteOffset` -// with `byteLength` as the size. Those properties must be validated against the -// real size of the backing ArrayBuffer: a spoofed object (or a view over a -// detached / resized buffer) can otherwise produce an out-of-bounds pointer or -// length and trigger a heap OOB read/write when consumed by writeBuffer. -// -// Dawn's node binding avoids this because it reads ByteOffset()/ByteLength() -// from the engine's typed-array view object (Napi), whose invariants the JS -// engine guarantees. Since JSI exposes these only as user-readable properties, -// we must validate them ourselves: byteOffset + byteLength <= buffer size. -// -// WebGPU is only available on Graphite (Dawn) builds, so these are gated on -// the Graphite backend. -describe("ArrayBuffer bounds", () => { - // -- Correctness of the legitimate offset path ------------------------------- - - itRunsWithGraphite( - "writes a typed-array view that has a non-zero byteOffset", - async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - // A Float32Array view starting at element 1 of a 4-element buffer. - const backing = new Float32Array([10, 20, 30, 40]); - const view = backing.subarray(1, 3); // [20, 30], byteOffset = 4 - const size = view.byteLength; // 8 bytes - - const src = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, - }); - const readBuffer = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - device.queue.writeBuffer(src, 0, view); - const encoder = device.createCommandEncoder(); - encoder.copyBufferToBuffer(src, 0, readBuffer, 0, size); - device.queue.submit([encoder.finish()]); - return device.queue - .onSubmittedWorkDone() - .then(() => - readBuffer - .mapAsync(GPUMapMode.READ) - .then(() => - Array.from(new Float32Array(readBuffer.getMappedRange())) - ) - ); - }); - // Must read the SLICE, not the whole backing buffer. - expect(result).toEqual([20, 30]); - } - ); - - itRunsWithGraphite( - "respects dataOffset/size element arguments of writeBuffer", - async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - const data = new Uint32Array([1, 2, 3, 4]); - const size = 2 * data.BYTES_PER_ELEMENT; // copy elements [1,2] - - const src = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, - }); - const readBuffer = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - // dataOffset = 1 element, size = 2 elements -> [2, 3] - device.queue.writeBuffer(src, 0, data, 1, 2); - const encoder = device.createCommandEncoder(); - encoder.copyBufferToBuffer(src, 0, readBuffer, 0, size); - device.queue.submit([encoder.finish()]); - return device.queue - .onSubmittedWorkDone() - .then(() => - readBuffer - .mapAsync(GPUMapMode.READ) - .then(() => - Array.from(new Uint32Array(readBuffer.getMappedRange())) - ) - ); - }); - expect(result).toEqual([2, 3]); - } - ); - - itRunsWithGraphite( - "accepts a raw ArrayBuffer as the data source", - async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - const ab = new Uint8Array([5, 6, 7, 8]).buffer; // raw ArrayBuffer - const size = ab.byteLength; - - const src = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, - }); - const readBuffer = device.createBuffer({ - size, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - device.queue.writeBuffer(src, 0, ab); - const encoder = device.createCommandEncoder(); - encoder.copyBufferToBuffer(src, 0, readBuffer, 0, size); - device.queue.submit([encoder.finish()]); - return device.queue - .onSubmittedWorkDone() - .then(() => - readBuffer - .mapAsync(GPUMapMode.READ) - .then(() => - Array.from(new Uint8Array(readBuffer.getMappedRange())) - ) - ); - }); - expect(result).toEqual([5, 6, 7, 8]); - } - ); - - // -- Out-of-bounds rejection ------------------------------------------------- - // The following cases MUST throw rather than read/write out of bounds. They - // pass once fromJSI validates byteOffset + byteLength against the real buffer - // size. Without that fix they may corrupt memory / crash instead of throwing. - - itRunsWithGraphite( - "rejects a spoofed BufferSource whose byteLength exceeds the buffer", - async () => { - await expect( - surface.eval((Skia) => { - const device = Skia.getDevice(); - const realBuffer = new ArrayBuffer(4); - // Looks like a TypedArray to native code, but lies about its size. - const spoofed = { - buffer: realBuffer, - byteOffset: 0, - byteLength: 1 << 24, // 16 MB, far beyond the 4-byte backing store - BYTES_PER_ELEMENT: 1, - }; - const dst = device.createBuffer({ - size: 256, - usage: GPUBufferUsage.COPY_DST, - }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - device.queue.writeBuffer(dst, 0, spoofed as any); - return true; - }) - ).rejects.toBeDefined(); - } - ); - - itRunsWithGraphite( - "rejects a spoofed BufferSource whose byteOffset is past the end", - async () => { - await expect( - surface.eval((Skia) => { - const device = Skia.getDevice(); - const realBuffer = new ArrayBuffer(4); - const spoofed = { - buffer: realBuffer, - byteOffset: 1 << 24, - byteLength: 4, - BYTES_PER_ELEMENT: 1, - }; - const dst = device.createBuffer({ - size: 256, - usage: GPUBufferUsage.COPY_DST, - }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - device.queue.writeBuffer(dst, 0, spoofed as any); - return true; - }) - ).rejects.toBeDefined(); - } - ); - - itRunsWithGraphite( - "rejects a BufferSource with a negative byteOffset", - async () => { - await expect( - surface.eval((Skia) => { - const device = Skia.getDevice(); - const realBuffer = new ArrayBuffer(16); - const spoofed = { - buffer: realBuffer, - byteOffset: -8, // wraps to a huge size_t in native code - byteLength: 8, - BYTES_PER_ELEMENT: 1, - }; - const dst = device.createBuffer({ - size: 256, - usage: GPUBufferUsage.COPY_DST, - }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - device.queue.writeBuffer(dst, 0, spoofed as any); - return true; - }) - ).rejects.toBeDefined(); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ComputeShader.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ComputeShader.spec.tsx deleted file mode 100644 index 7259627d68..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ComputeShader.spec.tsx +++ /dev/null @@ -1,274 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (ComputeShader.spec.ts). Runs a matrix -// multiplication on a compute pipeline and checks the GPU result against a JS -// reference. WebGPU is only available on Graphite (Dawn) builds. -const multiplyMatrices = (m1: number[], m2: number[]) => { - const rows1 = m1[0], - cols1 = m1[1]; - const cols2 = m2[1]; - const result: number[] = new Array(2 + rows1 * cols2); - result[0] = rows1; - result[1] = cols2; - - for (let i = 0; i < rows1; i++) { - for (let j = 0; j < cols2; j++) { - let sum = 0; - for (let k = 0; k < cols1; k++) { - sum += m1[2 + i * cols1 + k] * m2[2 + k * cols2 + j]; - } - result[2 + i * cols2 + j] = sum; - } - } - return result; -}; - -const makeMatrix = (rows: number, columns: number) => { - const m: number[] = new Array(rows * columns + 2); - m[0] = rows; - m[1] = columns; - for (let i = 2; i < m.length; i++) { - m[i] = Math.random(); - } - return m; -}; - -const SHADER = ` -struct Matrix { - size : vec2, - numbers: array, -} - -@group(0) @binding(0) var firstMatrix : Matrix; -@group(0) @binding(1) var secondMatrix : Matrix; -@group(0) @binding(2) var resultMatrix : Matrix; - -@compute @workgroup_size(8, 8) -fn main(@builtin(global_invocation_id) global_id : vec3) { - // Guard against out-of-bounds work group sizes - if (global_id.x >= u32(firstMatrix.size.x) || global_id.y >= u32(secondMatrix.size.y)) { - return; - } - - resultMatrix.size = vec2(firstMatrix.size.x, secondMatrix.size.y); - - let resultCell = vec2(global_id.x, global_id.y); - var result = 0.0; - for (var i = 0u; i < u32(firstMatrix.size.y); i = i + 1u) { - let a = i + resultCell.x * u32(firstMatrix.size.y); - let b = resultCell.y + i * u32(secondMatrix.size.y); - result = result + firstMatrix.numbers[a] * secondMatrix.numbers[b]; - } - - let index = resultCell.y + resultCell.x * u32(secondMatrix.size.y); - resultMatrix.numbers[index] = result; -} -`; - -describe("Compute Shader", () => { - itRunsWithGraphite("matrix multiplication", async () => { - const rows = 16; - const columns = 16; - const m1 = makeMatrix(rows, columns); - const m2 = makeMatrix(rows, columns); - - const result = await surface.eval( - (Skia, { firstMatrixRaw, secondMatrixRaw, rows1, columns1, shader }) => { - const device = Skia.getDevice(); - const firstMatrix = new Float32Array(firstMatrixRaw); - const secondMatrix = new Float32Array(secondMatrixRaw); - const gpuBufferFirstMatrix = device.createBuffer({ - mappedAtCreation: true, - size: firstMatrix.byteLength, - usage: GPUBufferUsage.STORAGE, - }); - new Float32Array(gpuBufferFirstMatrix.getMappedRange()).set( - firstMatrix - ); - gpuBufferFirstMatrix.unmap(); - - const gpuBufferSecondMatrix = device.createBuffer({ - mappedAtCreation: true, - size: secondMatrix.byteLength, - usage: GPUBufferUsage.STORAGE, - }); - new Float32Array(gpuBufferSecondMatrix.getMappedRange()).set( - secondMatrix - ); - gpuBufferSecondMatrix.unmap(); - - const resultMatrixBufferSize = - Float32Array.BYTES_PER_ELEMENT * - (2 + firstMatrix[0] * secondMatrix[1]); - const resultMatrixBuffer = device.createBuffer({ - size: resultMatrixBufferSize, - usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, - }); - - const shaderModule = device.createShaderModule({ code: shader }); - const computePipeline = device.createComputePipeline({ - layout: "auto", - compute: { module: shaderModule, entryPoint: "main" }, - }); - - const bindGroup = device.createBindGroup({ - layout: computePipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: { buffer: gpuBufferFirstMatrix } }, - { binding: 1, resource: { buffer: gpuBufferSecondMatrix } }, - { binding: 2, resource: { buffer: resultMatrixBuffer } }, - ], - }); - - const commandEncoder = device.createCommandEncoder(); - const passEncoder = commandEncoder.beginComputePass(); - passEncoder.setPipeline(computePipeline); - passEncoder.setBindGroup(0, bindGroup); - passEncoder.dispatchWorkgroups( - Math.ceil(rows1 / 8), - Math.ceil(columns1 / 8) - ); - passEncoder.end(); - - const gpuReadBuffer = device.createBuffer({ - size: resultMatrixBufferSize, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - commandEncoder.copyBufferToBuffer( - resultMatrixBuffer, - 0, - gpuReadBuffer, - 0, - resultMatrixBufferSize - ); - device.queue.submit([commandEncoder.finish()]); - - return gpuReadBuffer.mapAsync(GPUMapMode.READ).then(() => { - const r = Array.from( - new Float32Array(gpuReadBuffer.getMappedRange()) - ); - gpuReadBuffer.unmap(); - return r; - }); - }, - { - firstMatrixRaw: m1, - secondMatrixRaw: m2, - rows1: rows, - columns1: columns, - shader: SHADER, - } - ); - - expect(result.length).toBe(16 * 16 + 2); - expect(result.some((x) => x !== 0)).toBe(true); - const reference = multiplyMatrices(m1, m2); - for (let i = 0; i < result.length; i++) { - expect(result[i]).toBeCloseTo(reference[i], 5); - } - }); - - itRunsWithGraphite("async matrix multiplication", async () => { - const rows = 16; - const columns = 16; - const m1 = makeMatrix(rows, columns); - const m2 = makeMatrix(rows, columns); - - const result = await surface.eval( - (Skia, { firstMatrixRaw, secondMatrixRaw, rows1, columns1, shader }) => { - const device = Skia.getDevice(); - const firstMatrix = new Float32Array(firstMatrixRaw); - const secondMatrix = new Float32Array(secondMatrixRaw); - const gpuBufferFirstMatrix = device.createBuffer({ - mappedAtCreation: true, - size: firstMatrix.byteLength, - usage: GPUBufferUsage.STORAGE, - }); - new Float32Array(gpuBufferFirstMatrix.getMappedRange()).set( - firstMatrix - ); - gpuBufferFirstMatrix.unmap(); - - const gpuBufferSecondMatrix = device.createBuffer({ - mappedAtCreation: true, - size: secondMatrix.byteLength, - usage: GPUBufferUsage.STORAGE, - }); - new Float32Array(gpuBufferSecondMatrix.getMappedRange()).set( - secondMatrix - ); - gpuBufferSecondMatrix.unmap(); - - const resultMatrixBufferSize = - Float32Array.BYTES_PER_ELEMENT * - (2 + firstMatrix[0] * secondMatrix[1]); - const resultMatrixBuffer = device.createBuffer({ - size: resultMatrixBufferSize, - usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, - }); - - const shaderModule = device.createShaderModule({ code: shader }); - return device - .createComputePipelineAsync({ - layout: "auto", - compute: { module: shaderModule, entryPoint: "main" }, - }) - .then((computePipeline) => { - const bindGroup = device.createBindGroup({ - layout: computePipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: { buffer: gpuBufferFirstMatrix } }, - { binding: 1, resource: { buffer: gpuBufferSecondMatrix } }, - { binding: 2, resource: { buffer: resultMatrixBuffer } }, - ], - }); - - const commandEncoder = device.createCommandEncoder(); - const passEncoder = commandEncoder.beginComputePass(); - passEncoder.setPipeline(computePipeline); - passEncoder.setBindGroup(0, bindGroup); - passEncoder.dispatchWorkgroups( - Math.ceil(rows1 / 8), - Math.ceil(columns1 / 8) - ); - passEncoder.end(); - - const gpuReadBuffer = device.createBuffer({ - size: resultMatrixBufferSize, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - commandEncoder.copyBufferToBuffer( - resultMatrixBuffer, - 0, - gpuReadBuffer, - 0, - resultMatrixBufferSize - ); - device.queue.submit([commandEncoder.finish()]); - - return gpuReadBuffer.mapAsync(GPUMapMode.READ).then(() => { - const r = Array.from( - new Float32Array(gpuReadBuffer.getMappedRange()) - ); - gpuReadBuffer.unmap(); - return r; - }); - }); - }, - { - firstMatrixRaw: m1, - secondMatrixRaw: m2, - rows1: rows, - columns1: columns, - shader: SHADER, - } - ); - - expect(result.length).toBe(16 * 16 + 2); - expect(result.some((x) => x !== 0)).toBe(true); - const reference = multiplyMatrices(m1, m2); - for (let i = 0; i < result.length; i++) { - expect(result[i]).toBeCloseTo(reference[i], 5); - } - }); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/DawnToggles.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/DawnToggles.spec.tsx deleted file mode 100644 index 8ed415819a..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/DawnToggles.spec.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (DawnToggles.spec.ts). Exercises the -// non-standard, Dawn-only `dawnToggles` field on GPUDeviceDescriptor, which is -// parsed in cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h and chained onto -// the native wgpu::DeviceDescriptor in GPUAdapter::requestDevice. WebGPU is -// only available on Graphite (Dawn) builds, and dawnToggles is a Dawn -// extension, so these are gated on the Graphite backend. -describe("Dawn toggles", () => { - itRunsWithGraphite( - "requests a device with enabled and disabled dawnToggles", - async () => { - const result = await surface.eval(() => { - return navigator.gpu.requestAdapter().then((adapter) => - adapter! - .requestDevice({ - dawnToggles: { - enabledToggles: ["disable_symbol_renaming"], - disabledToggles: ["lazy_clear_resource_on_first_use"], - }, - }) - .then((device) => !!device) - ); - }); - expect(result).toBe(true); - } - ); - - itRunsWithGraphite( - "requests a device with no dawnToggles (unchanged behavior)", - async () => { - const result = await surface.eval(() => { - return navigator.gpu - .requestAdapter() - .then((adapter) => - adapter!.requestDevice().then((device) => !!device) - ); - }); - expect(result).toBe(true); - } - ); - - itRunsWithGraphite( - "ignores unknown toggle names without failing device creation", - async () => { - const result = await surface.eval(() => { - return navigator.gpu.requestAdapter().then((adapter) => - adapter! - .requestDevice({ - dawnToggles: { enabledToggles: ["this_toggle_does_not_exist"] }, - }) - .then((device) => !!device) - ); - }); - expect(result).toBe(true); - } - ); - - // The tests above only assert that requestDevice resolves, which is true - // whether or not the toggle is parsed and chained onto the device descriptor. - // This test instead activates a real toggle (skip_validation) and observes a - // behavioral difference, so it fails if dawnToggles ever stops being applied. - itRunsWithGraphite( - "applies skip_validation so a normally-invalid buffer creates without error", - async () => { - const result = await surface.eval(() => { - // MAP_READ may only be combined with COPY_DST and MAP_WRITE only with - // COPY_SRC, so MAP_READ | MAP_WRITE is a validation error by default. - // The buffer is never used on the GPU, so creating it with validation - // skipped is harmless on every backend. - const invalid = { - size: 16, - usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.MAP_WRITE, - }; - // A fresh adapter per device: an adapter only vends a single device. - return navigator.gpu - .requestAdapter() - .then((adapter) => adapter!.requestDevice()) - .then((control) => { - control.pushErrorScope("validation"); - control.createBuffer(invalid); - return control.popErrorScope(); - }) - .then((controlError) => - navigator.gpu - .requestAdapter() - .then((adapter) => - adapter!.requestDevice({ - dawnToggles: { enabledToggles: ["skip_validation"] }, - }) - ) - .then((toggled) => { - toggled.pushErrorScope("validation"); - toggled.createBuffer(invalid); - return toggled.popErrorScope(); - }) - .then((toggledError) => ({ - controlHadError: controlError !== null, - toggledHadError: toggledError !== null, - })) - ); - }); - // The operation is genuinely invalid on this build (guards against the - // test silently passing because the buffer became valid). - expect(result.controlHadError).toBe(true); - // skip_validation took effect, which is only possible if dawnToggles was - // parsed and chained onto the device descriptor. - expect(result.toggledHadError).toBe(false); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ErrorScope.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ErrorScope.spec.tsx deleted file mode 100644 index 13fe26c4c1..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ErrorScope.spec.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (ErrorScope.spec.ts). Exercises -// pushErrorScope/popErrorScope validation capture. WebGPU is only available on -// Graphite (Dawn) builds. -describe("Error Scope", () => { - itRunsWithGraphite( - "should capture validation error when creating sampler with invalid maxAnisotropy", - async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - device.pushErrorScope("validation"); - device.createSampler({ - maxAnisotropy: 0, // Invalid, maxAnisotropy must be at least 1. - }); - return device.popErrorScope().then((error) => { - if (error) { - return { - hasError: true, - messageLength: error.message.length, - messageNotEmpty: error.message.length > 0, - }; - } - return { hasError: false, messageLength: 0, messageNotEmpty: false }; - }); - }); - - expect(result.hasError).toBe(true); - expect(result.messageNotEmpty).toBe(true); - expect(result.messageLength).toBeGreaterThan(0); - } - ); - - itRunsWithGraphite( - "should capture and return error messages from popErrorScope", - async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - // Invalid WGSL shader with syntax error (missing closing parenthesis) - const invalidShaderWGSL = `@fragment - fn main() -> @location(0) vec4f { - return vec4(1.0, 0.0, 0.0, 1.0; - }`; - device.pushErrorScope("validation"); - device.createShaderModule({ code: invalidShaderWGSL }); - return device.popErrorScope().then((error) => { - if (error) { - return { - hasError: true, - messageLength: error.message.length, - messageNotEmpty: error.message.length > 0, - messageContainsExpected: - error.message.includes("expected") || - error.message.includes("error") || - error.message.includes("parsing"), - }; - } - return { - hasError: false, - messageLength: 0, - messageNotEmpty: false, - messageContainsExpected: false, - }; - }); - }); - expect(result.hasError).toBe(true); - expect(result.messageNotEmpty).toBe(true); - expect(result.messageLength).toBeGreaterThan(0); - expect(result.messageContainsExpected).toBe(true); - } - ); - - itRunsWithGraphite("should return null when no error occurs", async () => { - const result = await surface.eval((Skia) => { - const device = Skia.getDevice(); - const validShaderWGSL = `@fragment - fn main() -> @location(0) vec4f { - return vec4(1.0, 0.0, 0.0, 1.0); - }`; - device.pushErrorScope("validation"); - // This should not generate any errors - device.createShaderModule({ code: validShaderWGSL }); - return device.popErrorScope().then((error) => ({ - hasError: error !== null, - })); - }); - expect(result.hasError).toBe(false); - }); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ExternalTexture.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ExternalTexture.spec.tsx deleted file mode 100644 index 16013ba7fe..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ExternalTexture.spec.tsx +++ /dev/null @@ -1,234 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (ExternalTexture.spec.ts), adapted to Skia. -// Exercises queue.copyExternalImageToTexture: decode an image via -// createImageBitmap, upload it into a GPUTexture, then either sample it through -// a textured quad or read the texture back directly. Self-validating via pixel -// readback (no snapshot assets). WebGPU is only available on Graphite (Dawn) -// builds; createImageBitmap is a native binding that may be unbound. - -const TEXTURED_QUAD_SHADER = /* wgsl */ ` - struct VsOut { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, - }; - - @vertex fn vs(@builtin(vertex_index) vid: u32) -> VsOut { - var positions = array( - vec2f(-1.0, -3.0), - vec2f(-1.0, 1.0), - vec2f( 3.0, 1.0), - ); - var uvs = array( - vec2f(0.0, 2.0), - vec2f(0.0, 0.0), - vec2f(2.0, 0.0), - ); - var out: VsOut; - out.position = vec4f(positions[vid], 0.0, 1.0); - out.uv = uvs[vid]; - return out; - } - - @group(0) @binding(0) var srcSampler: sampler; - @group(0) @binding(1) var srcTex: texture_2d; - - @fragment fn fs(in: VsOut) -> @location(0) vec4f { - return textureSample(srcTex, srcSampler, in.uv); - } -`; - -const isCreateImageBitmapBound = () => - surface.eval(() => typeof createImageBitmap === "function"); - -describe("External Textures", () => { - itRunsWithGraphite( - "uploads an ImageBitmap with copyExternalImageToTexture and samples it", - async () => { - if (!(await isCreateImageBitmapBound())) { - console.warn("createImageBitmap is not bound — skipping"); - return; - } - const result = await surface.eval( - (Skia, { shader }) => { - const SIZE = 64; - // Encode a solid-blue image, then decode it as an ImageBitmap. - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - offscreen.getCanvas().drawColor(Skia.Color("blue")); - offscreen.flush(); - const png = offscreen.makeImageSnapshot().encodeToBytes(); - - const device = Skia.getDevice(); - return createImageBitmap( - png.buffer as unknown as ImageBitmapSource - ).then((bitmap) => { - const format: GPUTextureFormat = "rgba8unorm"; - const texture = device.createTexture({ - size: [bitmap.width, bitmap.height], - format, - usage: - GPUTextureUsage.TEXTURE_BINDING | - GPUTextureUsage.COPY_DST | - GPUTextureUsage.RENDER_ATTACHMENT, - }); - device.queue.copyExternalImageToTexture( - { source: bitmap }, - { texture }, - { width: bitmap.width, height: bitmap.height } - ); - - const module = device.createShaderModule({ code: shader }); - const pipeline = device.createRenderPipeline({ - layout: "auto", - vertex: { module, entryPoint: "vs" }, - fragment: { module, entryPoint: "fs", targets: [{ format }] }, - primitive: { topology: "triangle-list" }, - }); - const sampler = device.createSampler({ - magFilter: "linear", - minFilter: "linear", - }); - const bindGroup = device.createBindGroup({ - layout: pipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: sampler }, - { binding: 1, resource: texture.createView() }, - ], - }); - - const target = device.createTexture({ - size: [SIZE, SIZE], - format, - usage: - GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, - }); - const bytesPerRow = SIZE * 4; - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - const encoder = device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - view: target.createView(), - clearValue: { r: 0, g: 0, b: 0, a: 1 }, - loadOp: "clear", - storeOp: "store", - }, - ], - }); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bindGroup); - pass.draw(3); - pass.end(); - encoder.copyTextureToBuffer( - { texture: target }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array( - readBuffer.getMappedRange().slice(0) - ); - readBuffer.unmap(); - bitmap.close(); - const offset = - (Math.floor(SIZE / 2) * SIZE + Math.floor(SIZE / 2)) * 4; - return [ - pixels[offset], - pixels[offset + 1], - pixels[offset + 2], - pixels[offset + 3], - ]; - }); - }); - }, - { shader: TEXTURED_QUAD_SHADER } - ); - const [r, g, b, a] = result; - // Sampled the solid-blue uploaded image. - expect(b).toBeGreaterThan(200); - expect(r).toBeLessThan(60); - expect(g).toBeLessThan(60); - expect(a).toBeGreaterThan(200); - } - ); - - itRunsWithGraphite( - "copyExternalImageToTexture flipY uploads rows bottom-up", - async () => { - if (!(await isCreateImageBitmapBound())) { - console.warn("createImageBitmap is not bound — skipping"); - return; - } - const result = await surface.eval((Skia) => { - const SIZE = 64; - // Top half red, bottom half blue. - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - const canvas = offscreen.getCanvas(); - const paint = Skia.Paint(); - paint.setColor(Skia.Color("red")); - canvas.drawRect(Skia.XYWHRect(0, 0, SIZE, SIZE / 2), paint); - paint.setColor(Skia.Color("blue")); - canvas.drawRect(Skia.XYWHRect(0, SIZE / 2, SIZE, SIZE / 2), paint); - offscreen.flush(); - const png = offscreen.makeImageSnapshot().encodeToBytes(); - - const device = Skia.getDevice(); - return createImageBitmap( - png.buffer as unknown as ImageBitmapSource - ).then((bitmap) => { - const format: GPUTextureFormat = "rgba8unorm"; - const texture = device.createTexture({ - size: [bitmap.width, bitmap.height], - format, - usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, - }); - // flipY: source row 0 (top, red) ends up at the bottom of the - // texture, so the texture's top row is the source's bottom (blue). - device.queue.copyExternalImageToTexture( - { source: bitmap, flipY: true }, - { texture }, - { width: bitmap.width, height: bitmap.height } - ); - - const bytesPerRow = SIZE * 4; - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - const encoder = device.createCommandEncoder(); - encoder.copyTextureToBuffer( - { texture }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array(readBuffer.getMappedRange().slice(0)); - readBuffer.unmap(); - bitmap.close(); - // Column center, top row (y=2) and bottom row (y=SIZE-2). - const cx = Math.floor(SIZE / 2); - const top = (2 * SIZE + cx) * 4; - const bottom = ((SIZE - 2) * SIZE + cx) * 4; - return { - top: [pixels[top], pixels[top + 1], pixels[top + 2]], - bottom: [pixels[bottom], pixels[bottom + 1], pixels[bottom + 2]], - }; - }); - }); - }); - // After flipY, the texture top row is blue and the bottom row is red. - expect(result.top[2]).toBeGreaterThan(200); // blue - expect(result.top[0]).toBeLessThan(60); - expect(result.bottom[0]).toBeGreaterThan(200); // red - expect(result.bottom[2]).toBeLessThan(60); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ImageBitmapBounds.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ImageBitmapBounds.spec.tsx deleted file mode 100644 index 6b0bc641ad..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ImageBitmapBounds.spec.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// These tests exercise the same BufferSource bounds checking as -// ArrayBufferBounds.spec.tsx, but through the non-standard createImageBitmap -// overload that accepts an ArrayBuffer / TypedArray of encoded image bytes. -// -// That path must reuse the shared rnwgpu::ArrayBuffer converter -// (cpp/rnwgpu/ArrayBuffer.h), so a spoofed BufferSource that lies about -// byteOffset / byteLength is rejected rather than producing an out-of-bounds -// read when the bytes are copied. -// -// NOTE: createImageBitmap is a native-only (non-standard) binding. It is not -// bound in Skia's runtime yet, so each test self-skips (with a warning) until -// the binding is installed in RNSkManager. Once createImageBitmap is exposed, -// these run automatically on Graphite builds. They are skipped on web (the -// overload is native-only) via the Graphite gate. - -// Returns true when the connected device exposes a createImageBitmap binding. -// Until the native binding lands these specs are inert rather than vacuously -// passing (any rejection — including "createImageBitmap is not defined" — -// would otherwise satisfy `.rejects`). -const isCreateImageBitmapBound = () => - surface.eval(() => typeof createImageBitmap === "function"); - -describe("createImageBitmap bounds", () => { - itRunsWithGraphite( - "rejects a spoofed BufferSource whose byteLength exceeds the buffer", - async () => { - if (!(await isCreateImageBitmapBound())) { - console.warn("createImageBitmap is not bound — skipping"); - return; - } - await expect( - surface.eval(() => { - const realBuffer = new ArrayBuffer(4); - const spoofed = { - buffer: realBuffer, - byteOffset: 0, - byteLength: 1 << 24, // 16 MB, far beyond the 4-byte backing store - BYTES_PER_ELEMENT: 1, - }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return createImageBitmap(spoofed as any).then(() => true); - }) - ).rejects.toBeDefined(); - } - ); - - itRunsWithGraphite( - "rejects a spoofed BufferSource whose byteOffset is past the end", - async () => { - if (!(await isCreateImageBitmapBound())) { - console.warn("createImageBitmap is not bound — skipping"); - return; - } - await expect( - surface.eval(() => { - const realBuffer = new ArrayBuffer(4); - const spoofed = { - buffer: realBuffer, - byteOffset: 1 << 24, - byteLength: 4, - BYTES_PER_ELEMENT: 1, - }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return createImageBitmap(spoofed as any).then(() => true); - }) - ).rejects.toBeDefined(); - } - ); - - itRunsWithGraphite( - "rejects a BufferSource with a negative byteOffset", - async () => { - if (!(await isCreateImageBitmapBound())) { - console.warn("createImageBitmap is not bound — skipping"); - return; - } - await expect( - surface.eval(() => { - const realBuffer = new ArrayBuffer(16); - const spoofed = { - buffer: realBuffer, - byteOffset: -8, // wraps to a huge size_t in native code - byteLength: 8, - BYTES_PER_ELEMENT: 1, - }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return createImageBitmap(spoofed as any).then(() => true); - }) - ).rejects.toBeDefined(); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/ImportExternalTexture.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/ImportExternalTexture.spec.tsx deleted file mode 100644 index 0e575eb6c5..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/ImportExternalTexture.spec.tsx +++ /dev/null @@ -1,325 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (ImportExternalTexture.spec.ts), adapted to -// Skia's NativeBuffer API as the external-texture source (Skia has no -// VideoFrame). Draws a known solid color into an SkImage, wraps it as a native -// buffer (CVPixelBufferRef / AHardwareBuffer), imports it as a -// GPUExternalTexture, samples it through a render pass, reads the result back, -// and checks the sampled color matches. WebGPU is only available on Graphite -// (Dawn) builds. - -// NativeBuffer is iOS/Android only, and unavailable on the API-21 Fabric -// Android emulator (mirrors NativeBuffer.spec.tsx's shouldNativeBufferTestRun). -const supportsNativeBuffer = () => { - if (surface.OS !== "ios" && surface.OS !== "android") { - return false; - } - if (surface.arch === "fabric" && surface.OS === "android") { - return false; - } - return true; -}; - -describe("ImportExternalTexture", () => { - itRunsWithGraphite( - "imports a NativeBuffer as an external texture and samples it", - async () => { - if (!supportsNativeBuffer()) { - return; - } - const result = await surface.eval((Skia) => { - const SIZE = 64; - - // 1. Draw a solid red image and wrap it as a native buffer. - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - const canvas = offscreen.getCanvas(); - canvas.drawColor(Skia.Color("red")); - offscreen.flush(); - const image = offscreen.makeImageSnapshot(); - const nativeBuffer = Skia.NativeBuffer.MakeFromImage(image); - - const device = Skia.getDevice(); - try { - // 2. Import it. The GPUExternalTexture owns the shared-memory access - // window; there is no createTexture / beginAccess to manage. - // Skia's binding accepts the native buffer pointer as `source` (see - // the SkiaGPUExternalTextureDescriptor overload it adds to GPUDevice). - const externalTexture = device.importExternalTexture({ - source: nativeBuffer, - label: "test-frame", - }); - - // 3. Sample the external texture into a render target. - const module = device.createShaderModule({ - code: /* wgsl */ ` - struct VsOut { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, - }; - - @vertex fn vs(@builtin(vertex_index) vid: u32) -> VsOut { - var positions = array( - vec2f(-1.0, -3.0), - vec2f(-1.0, 1.0), - vec2f( 3.0, 1.0), - ); - var uvs = array( - vec2f(0.0, 2.0), - vec2f(0.0, 0.0), - vec2f(2.0, 0.0), - ); - var out: VsOut; - out.position = vec4f(positions[vid], 0.0, 1.0); - out.uv = uvs[vid]; - return out; - } - - @group(0) @binding(0) var srcTex: texture_external; - @group(0) @binding(1) var srcSampler: sampler; - - @fragment fn fs(in: VsOut) -> @location(0) vec4f { - return textureSampleBaseClampToEdge(srcTex, srcSampler, in.uv); - } - `, - }); - const format: GPUTextureFormat = "rgba8unorm"; - const pipeline = device.createRenderPipeline({ - layout: "auto", - vertex: { module, entryPoint: "vs" }, - fragment: { module, entryPoint: "fs", targets: [{ format }] }, - primitive: { topology: "triangle-list" }, - }); - const sampler = device.createSampler({ - magFilter: "linear", - minFilter: "linear", - }); - const bindGroup = device.createBindGroup({ - layout: pipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: externalTexture }, - { binding: 1, resource: sampler }, - ], - }); - - const target = device.createTexture({ - size: [SIZE, SIZE], - format, - usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, - }); - const bytesPerRow = SIZE * 4; // 256, already 256-byte aligned - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - const encoder = device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - view: target.createView(), - clearValue: { r: 0, g: 0, b: 0, a: 1 }, - loadOp: "clear", - storeOp: "store", - }, - ], - }); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bindGroup); - pass.draw(3); - pass.end(); - encoder.copyTextureToBuffer( - { texture: target }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - // End the access window now that the sampling work is submitted. - externalTexture.destroy(); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array(readBuffer.getMappedRange().slice(0)); - readBuffer.unmap(); - // Release the native buffer: all GPU work referencing it is - // submitted and the pixels have been read back. - Skia.NativeBuffer.Release(nativeBuffer); - // Center pixel. - const offset = - (Math.floor(SIZE / 2) * SIZE + Math.floor(SIZE / 2)) * 4; - return [ - pixels[offset], - pixels[offset + 1], - pixels[offset + 2], - pixels[offset + 3], - ]; - }); - } catch (e) { - Skia.NativeBuffer.Release(nativeBuffer); - throw e; - } - }); - const [r, g, b, a] = result; - // Sampled the solid-red source: red high, green/blue low, opaque. - expect(r).toBeGreaterThan(200); - expect(g).toBeLessThan(60); - expect(b).toBeLessThan(60); - expect(a).toBeGreaterThan(200); - } - ); - - // A solid color can't catch a broken UV mapping (every texel is the same), so - // this samples a 4-quadrant image and checks all four distinct colors survive - // — a collapsed/degenerate transform would repeat or blend them. - itRunsWithGraphite( - "preserves the 2D layout of a non-uniform external texture", - async () => { - if (!supportsNativeBuffer()) { - return; - } - const result = await surface.eval((Skia) => { - const SIZE = 64; - const half = SIZE / 2; - // Four distinct quadrants: TL red, TR green, BL blue, BR yellow. - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - const canvas = offscreen.getCanvas(); - const paint = Skia.Paint(); - const quadrants: [string, number, number][] = [ - ["red", 0, 0], - ["lime", half, 0], - ["blue", 0, half], - ["yellow", half, half], - ]; - quadrants.forEach(([color, x, y]) => { - paint.setColor(Skia.Color(color)); - canvas.drawRect(Skia.XYWHRect(x, y, half, half), paint); - }); - offscreen.flush(); - const nativeBuffer = Skia.NativeBuffer.MakeFromImage( - offscreen.makeImageSnapshot() - ); - - const device = Skia.getDevice(); - try { - const externalTexture = device.importExternalTexture({ - source: nativeBuffer, - label: "grid-frame", - }); - const module = device.createShaderModule({ - code: /* wgsl */ ` - struct VsOut { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, - }; - @vertex fn vs(@builtin(vertex_index) vid: u32) -> VsOut { - var positions = array( - vec2f(-1.0, -3.0), vec2f(-1.0, 1.0), vec2f(3.0, 1.0), - ); - var uvs = array( - vec2f(0.0, 2.0), vec2f(0.0, 0.0), vec2f(2.0, 0.0), - ); - var out: VsOut; - out.position = vec4f(positions[vid], 0.0, 1.0); - out.uv = uvs[vid]; - return out; - } - @group(0) @binding(0) var srcTex: texture_external; - @group(0) @binding(1) var srcSampler: sampler; - @fragment fn fs(in: VsOut) -> @location(0) vec4f { - return textureSampleBaseClampToEdge(srcTex, srcSampler, in.uv); - } - `, - }); - const format: GPUTextureFormat = "rgba8unorm"; - const pipeline = device.createRenderPipeline({ - layout: "auto", - vertex: { module, entryPoint: "vs" }, - fragment: { module, entryPoint: "fs", targets: [{ format }] }, - primitive: { topology: "triangle-list" }, - }); - // Nearest filtering so quadrant centers read back as pure colors. - const sampler = device.createSampler({}); - const bindGroup = device.createBindGroup({ - layout: pipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: externalTexture }, - { binding: 1, resource: sampler }, - ], - }); - - const target = device.createTexture({ - size: [SIZE, SIZE], - format, - usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, - }); - const bytesPerRow = SIZE * 4; - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - const encoder = device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - view: target.createView(), - clearValue: { r: 0, g: 0, b: 0, a: 1 }, - loadOp: "clear", - storeOp: "store", - }, - ], - }); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bindGroup); - pass.draw(3); - pass.end(); - encoder.copyTextureToBuffer( - { texture: target }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - externalTexture.destroy(); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array(readBuffer.getMappedRange().slice(0)); - readBuffer.unmap(); - Skia.NativeBuffer.Release(nativeBuffer); - // Sample the center of each rendered quadrant. - const q = SIZE / 4; - const at = (x: number, y: number) => { - const o = (y * SIZE + x) * 4; - return [pixels[o], pixels[o + 1], pixels[o + 2]]; - }; - return [at(q, q), at(3 * q, q), at(q, 3 * q), at(3 * q, 3 * q)]; - }); - } catch (e) { - Skia.NativeBuffer.Release(nativeBuffer); - throw e; - } - }); - // Classify each sampled quadrant by dominant channels. Orientation- - // agnostic: a correct 2D mapping yields the four distinct source colors - // (in some orientation); a collapse would repeat or blend them. - const classify = ([r, g, b]: number[]) => { - if (r > 180 && g > 180 && b < 80) { - return "yellow"; - } - if (r > 180 && g < 80 && b < 80) { - return "red"; - } - if (r < 80 && g > 180 && b < 80) { - return "green"; - } - if (r < 80 && g < 80 && b > 180) { - return "blue"; - } - return "other"; - }; - expect(result.map(classify).sort()).toEqual([ - "blue", - "green", - "red", - "yellow", - ]); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/SharedTextureMemory.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/SharedTextureMemory.spec.tsx deleted file mode 100644 index f963d488b1..0000000000 --- a/packages/skia/src/renderer/__tests__/e2e/SharedTextureMemory.spec.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import { surface, itRunsWithGraphite } from "../setup"; - -// Ported from react-native-webgpu (SharedTextureMemory.spec.ts), adapted to -// Skia's NativeBuffer API as the shared-memory source (Skia has no VideoFrame). -// Draws a known solid color into an SkImage, wraps it as a native buffer -// (CVPixelBufferRef / AHardwareBuffer), imports it via -// device.importSharedTextureMemory, creates a texture aliasing it, samples it -// through a textured quad, reads the result back, and checks the sampled color. -// WebGPU is only available on Graphite (Dawn) builds, and NativeBuffer only on -// iOS/Android (not on the API-21 Fabric Android emulator). - -const SHARED_TEXTURE_SHADER = /* wgsl */ ` - struct VsOut { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, - }; - - @vertex fn vs(@builtin(vertex_index) vid: u32) -> VsOut { - var positions = array( - vec2f(-1.0, -3.0), - vec2f(-1.0, 1.0), - vec2f( 3.0, 1.0), - ); - var uvs = array( - vec2f(0.0, 2.0), - vec2f(0.0, 0.0), - vec2f(2.0, 0.0), - ); - var out: VsOut; - out.position = vec4f(positions[vid], 0.0, 1.0); - out.uv = uvs[vid]; - return out; - } - - @group(0) @binding(0) var srcTex: texture_2d; - @group(0) @binding(1) var srcSampler: sampler; - - @fragment fn fs(in: VsOut) -> @location(0) vec4f { - return textureSample(srcTex, srcSampler, in.uv); - } -`; - -// NativeBuffer is iOS/Android only, and unavailable on the API-21 Fabric -// Android emulator (mirrors NativeBuffer.spec.tsx's shouldNativeBufferTestRun). -const supportsNativeBuffer = () => { - if (surface.OS !== "ios" && surface.OS !== "android") { - return false; - } - if (surface.arch === "fabric" && surface.OS === "android") { - return false; - } - return true; -}; - -describe("SharedTextureMemory", () => { - itRunsWithGraphite( - "imports a NativeBuffer and samples it through a textured quad", - async () => { - if (!supportsNativeBuffer()) { - return; - } - const result = await surface.eval( - (Skia, { shader }) => { - const SIZE = 64; - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - offscreen.getCanvas().drawColor(Skia.Color("red")); - offscreen.flush(); - const nativeBuffer = Skia.NativeBuffer.MakeFromImage( - offscreen.makeImageSnapshot() - ); - - const device = Skia.getDevice(); - try { - // importSharedTextureMemory is a Skia extension to GPUDevice (see - // the types in src/skia/types/WebGPU.ts). - const memory = device.importSharedTextureMemory({ - handle: nativeBuffer, - label: "test-frame", - }); - const texture = memory.createTexture(); - // beginAccess returns void and throws on failure. - memory.beginAccess(texture, true); - - const module = device.createShaderModule({ code: shader }); - const format: GPUTextureFormat = "rgba8unorm"; - const pipeline = device.createRenderPipeline({ - layout: "auto", - vertex: { module, entryPoint: "vs" }, - fragment: { module, entryPoint: "fs", targets: [{ format }] }, - primitive: { topology: "triangle-list" }, - }); - const sampler = device.createSampler({ - magFilter: "linear", - minFilter: "linear", - }); - const bindGroup = device.createBindGroup({ - layout: pipeline.getBindGroupLayout(0), - entries: [ - { binding: 0, resource: texture.createView() }, - { binding: 1, resource: sampler }, - ], - }); - - const target = device.createTexture({ - size: [SIZE, SIZE], - format, - usage: - GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, - }); - const bytesPerRow = SIZE * 4; // 256, already 256-byte aligned - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - const encoder = device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - view: target.createView(), - clearValue: { r: 0, g: 0, b: 0, a: 1 }, - loadOp: "clear", - storeOp: "store", - }, - ], - }); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bindGroup); - pass.draw(3); - pass.end(); - encoder.copyTextureToBuffer( - { texture: target }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array( - readBuffer.getMappedRange().slice(0) - ); - readBuffer.unmap(); - memory.endAccess(texture); - texture.destroy(); - Skia.NativeBuffer.Release(nativeBuffer); - const offset = - (Math.floor(SIZE / 2) * SIZE + Math.floor(SIZE / 2)) * 4; - return [ - pixels[offset], - pixels[offset + 1], - pixels[offset + 2], - pixels[offset + 3], - ]; - }); - } catch (e) { - Skia.NativeBuffer.Release(nativeBuffer); - throw e; - } - }, - { shader: SHARED_TEXTURE_SHADER } - ); - const [r, g, b, a] = result; - // Sampled the solid-red source. - expect(r).toBeGreaterThan(200); - expect(g).toBeLessThan(60); - expect(b).toBeLessThan(60); - expect(a).toBeGreaterThan(200); - } - ); - - // Same as above, but with an *explicit* bind group layout - // (createBindGroupLayout + createPipelineLayout) instead of layout: "auto". - // This exercises the native BindGroupLayoutEntry conversion path, which - // "auto" layouts bypass entirely. - itRunsWithGraphite( - "samples a shared texture through an explicit bind group layout", - async () => { - if (!supportsNativeBuffer()) { - return; - } - const result = await surface.eval( - (Skia, { shader }) => { - const SIZE = 64; - const offscreen = Skia.Surface.MakeOffscreen(SIZE, SIZE)!; - offscreen.getCanvas().drawColor(Skia.Color("lime")); - offscreen.flush(); - const nativeBuffer = Skia.NativeBuffer.MakeFromImage( - offscreen.makeImageSnapshot() - ); - - const device = Skia.getDevice(); - try { - // importSharedTextureMemory is a Skia extension to GPUDevice (see - // the types in src/skia/types/WebGPU.ts). - const memory = device.importSharedTextureMemory({ - handle: nativeBuffer, - label: "test-frame", - }); - const texture = memory.createTexture(); - // beginAccess returns void and throws on failure. - memory.beginAccess(texture, true); - - const module = device.createShaderModule({ code: shader }); - const format: GPUTextureFormat = "rgba8unorm"; - const bindGroupLayout = device.createBindGroupLayout({ - entries: [ - { - binding: 0, - visibility: GPUShaderStage.FRAGMENT, - texture: {}, - }, - { - binding: 1, - visibility: GPUShaderStage.FRAGMENT, - sampler: {}, - }, - ], - }); - const pipeline = device.createRenderPipeline({ - layout: device.createPipelineLayout({ - bindGroupLayouts: [bindGroupLayout], - }), - vertex: { module, entryPoint: "vs" }, - fragment: { module, entryPoint: "fs", targets: [{ format }] }, - primitive: { topology: "triangle-list" }, - }); - const sampler = device.createSampler({ - magFilter: "linear", - minFilter: "linear", - }); - const bindGroup = device.createBindGroup({ - layout: bindGroupLayout, - entries: [ - { binding: 0, resource: texture.createView() }, - { binding: 1, resource: sampler }, - ], - }); - - const target = device.createTexture({ - size: [SIZE, SIZE], - format, - usage: - GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, - }); - const bytesPerRow = SIZE * 4; - const readBuffer = device.createBuffer({ - size: bytesPerRow * SIZE, - usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - }); - - const encoder = device.createCommandEncoder(); - const pass = encoder.beginRenderPass({ - colorAttachments: [ - { - view: target.createView(), - clearValue: { r: 0, g: 0, b: 0, a: 1 }, - loadOp: "clear", - storeOp: "store", - }, - ], - }); - pass.setPipeline(pipeline); - pass.setBindGroup(0, bindGroup); - pass.draw(3); - pass.end(); - encoder.copyTextureToBuffer( - { texture: target }, - { buffer: readBuffer, bytesPerRow }, - { width: SIZE, height: SIZE } - ); - device.queue.submit([encoder.finish()]); - - return readBuffer.mapAsync(GPUMapMode.READ).then(() => { - const pixels = new Uint8Array( - readBuffer.getMappedRange().slice(0) - ); - readBuffer.unmap(); - memory.endAccess(texture); - texture.destroy(); - Skia.NativeBuffer.Release(nativeBuffer); - const offset = - (Math.floor(SIZE / 2) * SIZE + Math.floor(SIZE / 2)) * 4; - return [ - pixels[offset], - pixels[offset + 1], - pixels[offset + 2], - pixels[offset + 3], - ]; - }); - } catch (e) { - Skia.NativeBuffer.Release(nativeBuffer); - throw e; - } - }, - { shader: SHARED_TEXTURE_SHADER } - ); - const [r, g, b, a] = result; - // Sampled the solid-green ("lime") source. - expect(g).toBeGreaterThan(200); - expect(r).toBeLessThan(60); - expect(b).toBeLessThan(60); - expect(a).toBeGreaterThan(200); - } - ); -}); diff --git a/packages/skia/src/renderer/__tests__/e2e/TextureInterop.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/TextureInterop.spec.tsx new file mode 100644 index 0000000000..d77e8c5b5a --- /dev/null +++ b/packages/skia/src/renderer/__tests__/e2e/TextureInterop.spec.tsx @@ -0,0 +1,86 @@ +import { AlphaType, ColorType } from "../../../skia/types"; +import { itRunsWithGraphite, surface } from "../setup"; + +// Covers the pointer-based interop surface with react-native-webgpu: +// Skia.getNativeDevice() and the +// MakeNativeTextureFromImage / MakeImageFromNativeTexture round trip. +// The pointers never cross the eval boundary (BigInt is not JSON +// serializable); everything runs on-device and only plain data comes back. +describe("Texture interop (Graphite)", () => { + itRunsWithGraphite("getNativeDevice() returns a device pointer", async () => { + const result = await surface.eval((Skia) => { + const device = Skia.getNativeDevice(); + if (typeof device !== "bigint") { + return `expected a bigint, got ${typeof device}`; + } + if (device === BigInt(0)) { + return "expected a non-null device pointer"; + } + // The pointer is stable for the process lifetime. + return Skia.getNativeDevice() === device ? "ok" : "pointer not stable"; + }); + expect(result).toBe("ok"); + }); + + itRunsWithGraphite( + "round-trips an SkImage through a native texture", + async () => { + const result = await surface.eval( + (Skia, ctx) => { + const size = 64; + const src = Skia.Surface.MakeOffscreen(size, size); + if (!src) { + return "could not create the source surface"; + } + const canvas = src.getCanvas(); + const paint = Skia.Paint(); + paint.setColor(Skia.Color("red")); + canvas.drawRect(Skia.XYWHRect(0, 0, size / 2, size), paint); + paint.setColor(Skia.Color("lime")); + canvas.drawRect(Skia.XYWHRect(size / 2, 0, size / 2, size), paint); + src.flush(); + const original = src.makeImageSnapshot(); + + // SkImage -> WGPUTexture pointer -> SkImage. The returned pointer + // carries the reference normally adopted by react-native-webgpu's + // adoptTexture(); the wrap below only borrows it, so this spec leaks + // one 64x64 texture per run — acceptable in a test. + const pointer = Skia.Image.MakeNativeTextureFromImage(original); + if (typeof pointer !== "bigint" || pointer === BigInt(0)) { + return "MakeNativeTextureFromImage did not return a pointer"; + } + const roundTripped = Skia.Image.MakeImageFromNativeTexture(pointer); + if (roundTripped.width() !== size || roundTripped.height() !== size) { + return `unexpected size ${roundTripped.width()}x${roundTripped.height()}`; + } + + // Draw the wrapped image so the texture is actually sampled, then + // read the result back through the canvas. + const dst = Skia.Surface.MakeOffscreen(size, size); + if (!dst) { + return "could not create the destination surface"; + } + dst.getCanvas().drawImage(roundTripped, 0, 0); + dst.flush(); + const pixels = dst.getCanvas().readPixels(0, 0, { + width: size, + height: size, + colorType: ctx.colorType, + alphaType: ctx.alphaType, + }); + if (!pixels) { + return "readPixels returned null"; + } + const px = (x: number, y: number) => + Array.from( + pixels.slice((y * size + x) * 4, (y * size + x) * 4 + 4) + ); + // One sample from the center of each half. + return [...px(16, 32), ...px(48, 32)]; + }, + { colorType: ColorType.RGBA_8888, alphaType: AlphaType.Unpremul } + ); + expect(result).toEqual([255, 0, 0, 255, 0, 255, 0, 255]); + } + ); +}); diff --git a/packages/skia/src/renderer/__tests__/setup.tsx b/packages/skia/src/renderer/__tests__/setup.tsx index 49c7b3fae9..4bf44472c4 100644 --- a/packages/skia/src/renderer/__tests__/setup.tsx +++ b/packages/skia/src/renderer/__tests__/setup.tsx @@ -132,9 +132,9 @@ const parseErrorResponse = (raw: Buffer): string | null => { // Registers a test that only runs against a device using the Graphite backend // (Dawn/WebGPU). The backend is only known after the websocket handshake, so — // like itSkipsOnWeb in react-native-webgpu — the guard is a runtime early -// return rather than it.skip at collection time. This also keeps the WebGPU -// specs inert in Node/Local mode and on Ganesh builds, where Skia.getDevice() -// would throw. +// return rather than it.skip at collection time. This also keeps the Graphite +// specs inert in Node/Local mode and on Ganesh builds, where +// Skia.getNativeDevice() would throw. export const itRunsWithGraphite = ( name: string, fn: () => Promise, @@ -420,9 +420,9 @@ interface TestingSurface { fontSize: number; OS: TestOS; arch: "paper" | "fabric"; - // True when the connected device runs the Graphite backend, i.e. the WebGPU - // API (navigator.gpu / Skia.getDevice()) is available. Always false in Node - // (LocalSurface) and on Ganesh builds. + // True when the connected device runs the Graphite backend, i.e. + // Skia.getNativeDevice() is available (see useClient.ts in the example + // app). Always false in Node (LocalSurface) and on Ganesh builds. graphite: boolean; } diff --git a/packages/skia/src/skia/types/Image/ImageFactory.ts b/packages/skia/src/skia/types/Image/ImageFactory.ts index d4e0ced489..04d13d0b8c 100644 --- a/packages/skia/src/skia/types/Image/ImageFactory.ts +++ b/packages/skia/src/skia/types/Image/ImageFactory.ts @@ -97,23 +97,32 @@ export interface ImageFactory { /** * Creates an SkImage from a WebGPU texture. - * This allows using textures rendered by WebGPU in Skia drawings. + * This allows using textures rendered by WebGPU in Skia drawings. The + * texture crosses the package boundary as a raw pointer: pass + * `texture.nativePointer` from a react-native-webgpu GPUTexture created on + * the shared device (importDevice(Skia.getNativeDevice())). The native side + * takes its own reference, so the handle stays valid even if the JS + * GPUTexture is garbage collected — but do not call texture.destroy() + * while the image is in use: destroy() releases the underlying GPU + * resource regardless of reference counts. * * Note: This method is only available when the Graphite backend is enabled. * - * @param texture - A GPUTexture object from the WebGPU API + * @param pointer - The WGPUTexture pointer (texture.nativePointer) * @returns An SkImage wrapping the texture, or throws if the texture is invalid */ - MakeImageFromTexture(texture: GPUTexture): SkImage; + MakeImageFromNativeTexture(pointer: bigint): SkImage; /** * Creates a WebGPU texture from an SkImage. - * This allows using Skia images in WebGPU rendering pipelines. + * This allows using Skia images in WebGPU rendering pipelines. The + * returned pointer carries one reference and must be adopted exactly once + * with react-native-webgpu's adoptTexture(), which owns it from then on. * * Note: This method is only available when the Graphite backend is enabled. * * @param image - An SkImage to convert to a texture - * @returns A GPUTexture containing the image data, or throws if conversion fails + * @returns A WGPUTexture pointer for adoptTexture(), or throws on failure */ - MakeTextureFromImage(image: SkImage): GPUTexture; + MakeNativeTextureFromImage(image: SkImage): bigint; } diff --git a/packages/skia/src/skia/types/Skia.ts b/packages/skia/src/skia/types/Skia.ts index be7f1fa6d7..fcbaf7bdf0 100644 --- a/packages/skia/src/skia/types/Skia.ts +++ b/packages/skia/src/skia/types/Skia.ts @@ -110,20 +110,10 @@ export interface Skia { NativeBuffer: NativeBufferFactory; Recorder(): JsiRecorder; /** - * Returns whether the Graphite backend is enabled and WebGPU is available. - * - * @returns true if Graphite/WebGPU is available, false otherwise + * Raw WGPUDevice pointer of Skia's Graphite device, as a BigInt. Pass it to + * react-native-webgpu's importDevice() to get a GPUDevice sharing Skia's + * device (zero-copy interop). Only available on Graphite builds; throws + * otherwise. */ - hasDevice(): boolean; - /** - * Returns the shared WebGPU device used by Skia's Graphite backend. - * This allows direct access to the GPU device for WebGPU operations. - * - * Note: This method is only available when the Graphite backend is enabled. - * Use hasDevice() to check availability before calling this method. - * - * @returns The GPUDevice used by Skia - * @throws Error if Graphite backend is not enabled - */ - getDevice(): GPUDevice; + getNativeDevice(): bigint; } diff --git a/packages/skia/src/skia/types/WebGPU.ts b/packages/skia/src/skia/types/WebGPU.ts deleted file mode 100644 index 7e8ee0c3ef..0000000000 --- a/packages/skia/src/skia/types/WebGPU.ts +++ /dev/null @@ -1,226 +0,0 @@ -import type { NativeBuffer } from "./NativeBuffer"; - -/** - * Make the WebGPU flag constants (`GPUBufferUsage`, `GPUColorWrite`, - * `GPUMapMode`, `GPUShaderStage`, `GPUTextureUsage`) available on the runtime - * that calls this. - * - * The native module installs these globals on the main JS runtime, but worklet - * runtimes (Reanimated UI, dedicated worklet runtimes, Vision Camera frame - * processors) start without them, so referencing the bare global inside a - * worklet yields `undefined`. Call `installWebGPU()` once at the top of a - * worklet to install them there: - * - * ```tsx - * import { installWebGPU } from "@shopify/react-native-skia"; - * - * const work = (device: GPUDevice) => { - * "worklet"; - * installWebGPU(); - * device.createBuffer({ - * usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, - * }); - * }; - * ``` - * - * `installWebGPU` is a native host function. When captured into a worklet, the - * Worklets serializer re-creates it on the worklet runtime, so calling it there - * installs the constants on that runtime. The values come from the native - * `wgpu::*Usage` enums, so they stay a single source of truth across runtimes. - * Calling it on a runtime that already has the constants is a safe no-op, and on - * web (where the constants are always global) it is a no-op too. - */ -export const installWebGPU: () => void = (() => { - const g = - typeof global !== "undefined" - ? (global as unknown as { installWebGPU?: () => void }) - : undefined; - return g && typeof g.installWebGPU === "function" - ? g.installWebGPU - : () => {}; -})(); - -// Skia's Graphite/Dawn backend extends the standard WebGPU API (typed by -// @webgpu/types) with a few Skia- and Dawn-specific entry points. These are -// only available on native (SK_GRAPHITE) builds, reachable through -// `Skia.getDevice()`. -// -// The exported interfaces below describe the descriptors and objects those -// entry points use; the `declare global` block augments the standard WebGPU -// interfaces so the new methods are typed without casting to `any`. - -/** - * Descriptor for {@link GPUDevice.importExternalTexture} when the source is a - * Skia NativeBuffer (Skia has no WebCodecs `VideoFrame`). - * - * `source` is the handle returned by `Skia.NativeBuffer.MakeFromImage`: a - * `CVPixelBufferRef` on Apple, an `AHardwareBuffer*` on Android. The caller - * owns its lifetime (release it with `Skia.NativeBuffer.Release`) and must keep - * it alive until the imported texture is destroyed. - */ -export interface SkiaGPUExternalTextureDescriptor extends GPUObjectDescriptorBase { - source: NativeBuffer; - /** Rotation applied while sampling, in degrees. One of 0 | 90 | 180 | 270. */ - rotation?: number; - /** Mirror horizontally while sampling. */ - mirrored?: boolean; -} - -/** - * Descriptor for {@link GPUDevice.importSharedTextureMemory}. `handle` is the - * NativeBuffer returned by `Skia.NativeBuffer.MakeFromImage` (see - * {@link SkiaGPUExternalTextureDescriptor} for the platform-specific types and - * lifetime rules). - */ -export interface GPUSharedTextureMemoryDescriptor extends GPUObjectDescriptorBase { - handle: NativeBuffer; -} - -/** - * The kind of native synchronization primitive a {@link GPUSharedFence} wraps, - * matching the `shared-fence-*` device feature names. Limited to the kinds - * react-native-skia targets (iOS/Metal and Android/Vulkan); `importSharedFence` - * accepts these and `export()` reports them. - */ -export type GPUSharedFenceType = - | "mtl-shared-event" - | "sync-fd" - | "vk-semaphore-opaque-fd"; - -/** - * Descriptor for {@link GPUDevice.importSharedFence}. - */ -export interface GPUSharedFenceDescriptor { - /** - * The fence kind to import. Must match a `shared-fence-*` feature enabled on - * the device. - */ - type: GPUSharedFenceType; - /** - * The raw native handle as a BigInt: an `id` pointer for - * `"mtl-shared-event"`, or an OS file descriptor for the `*-fd` kinds. - */ - handle: bigint; - label?: string; -} - -export interface GPUSharedFenceExportInfo { - type: GPUSharedFenceType; - /** - * An `id` pointer (Apple) or file descriptor (Android), as a - * BigInt. The caller takes ownership; e.g. an exported sync-fd must be closed - * once consumed. - */ - handle: bigint; -} - -/** - * A native GPU synchronization primitive shared across queues/APIs. Produced by - * {@link GPUSharedTextureMemory.endAccess}, consumed by - * {@link GPUSharedTextureMemory.beginAccess}, or imported from a consumer's - * fence with {@link GPUDevice.importSharedFence}. - */ -export interface GPUSharedFence { - readonly __brand: "GPUSharedFence"; - label: string; - export(): GPUSharedFenceExportInfo; -} - -/** A fence and the timeline value to wait for (0n for binary sync-fd fences). */ -export interface GPUSharedFenceState { - fence: GPUSharedFence; - signaledValue: bigint; -} - -/** - * The result of {@link GPUSharedTextureMemory.endAccess}: each fence is signaled - * at its `signaledValue` once Dawn's GPU work for the access completes. - */ -export interface GPUSharedTextureMemoryEndAccessState { - initialized: boolean; - fences: GPUSharedFenceState[]; -} - -/** - * Shared texture memory imported from a platform native buffer via - * {@link GPUDevice.importSharedTextureMemory}. Create a texture that aliases - * the memory, then bracket the GPU work that touches it with - * {@link GPUSharedTextureMemory.beginAccess} / {@link GPUSharedTextureMemory.endAccess}. - */ -export interface GPUSharedTextureMemory extends GPUObjectBase { - /** Create a texture that aliases the shared memory. */ - createTexture(descriptor?: GPUTextureDescriptor): GPUTexture; - /** - * Acquire the memory for GPU access. `initialized` marks whether the existing - * contents should be preserved (pass `true` for an already-rendered frame). - * Optional `fences` are wait fences: Dawn waits for each to reach its - * `signaledValue` before writing the surface. Throws if the access could not - * be acquired. - */ - beginAccess( - texture: GPUTexture, - initialized: boolean, - fences?: GPUSharedFenceState[] - ): void; - /** - * Release the memory after the GPU work that accessed it has been submitted, - * and return the fences Dawn produced for the access. Throws on failure. - */ - endAccess(texture: GPUTexture): GPUSharedTextureMemoryEndAccessState; -} - -/** - * Dawn-specific toggles, passed via {@link GPUDeviceDescriptor.dawnToggles} to - * `adapter.requestDevice`. This is a non-spec, Dawn-only extension; see Dawn's - * toggle list for valid names. - */ -export interface GPUDawnTogglesDescriptor { - enabledToggles?: string[]; - disabledToggles?: string[]; -} - -declare global { - interface GPUDeviceDescriptor { - /** Dawn-specific toggles (Skia/Graphite extension, non-spec). */ - dawnToggles?: GPUDawnTogglesDescriptor; - } - - interface GPUExternalTexture { - /** - * Skia extension: end the imported buffer's shared-memory access window and - * release the underlying resources. Call right after the `queue.submit()` - * that sampled this texture (never before). Idempotent, and also runs at - * garbage collection as a fallback. - */ - destroy(): void; - } - - interface GPUDevice { - /** - * Skia extension: import a NativeBuffer (from - * `Skia.NativeBuffer.MakeFromImage`) as a {@link GPUExternalTexture}, sampled - * with `texture_external` in WGSL. The returned texture owns the - * shared-memory access window; call `destroy()` on it after the sampling - * `queue.submit()`. - */ - importExternalTexture( - descriptor: SkiaGPUExternalTextureDescriptor - ): GPUExternalTexture; - /** - * Skia extension: import a NativeBuffer (from - * `Skia.NativeBuffer.MakeFromImage`) as {@link GPUSharedTextureMemory}, the - * lower-level path that lets you create an aliasing texture and manage the - * begin/end access window yourself. - */ - importSharedTextureMemory( - descriptor: GPUSharedTextureMemoryDescriptor - ): GPUSharedTextureMemory; - /** - * Skia extension: import a native synchronization primitive (an - * `id` on Apple, a sync-fd / VkSemaphore on Android) as a - * {@link GPUSharedFence}, e.g. to wait on a fence a consumer produced. The - * matching `shared-fence-*` feature must be enabled on the device. - */ - importSharedFence(descriptor: GPUSharedFenceDescriptor): GPUSharedFence; - } -} diff --git a/packages/skia/src/skia/types/index.ts b/packages/skia/src/skia/types/index.ts index be8fcf4f54..2d55392f42 100644 --- a/packages/skia/src/skia/types/index.ts +++ b/packages/skia/src/skia/types/index.ts @@ -30,7 +30,6 @@ export * from "./Size"; export * from "./Paragraph"; export * from "./Matrix4"; export * from "./NativeBuffer"; -export * from "./WebGPU"; export * from "./Recorder"; export * from "./Video"; export * from "./Skottie"; diff --git a/packages/skia/src/skia/web/JsiSkImageFactory.ts b/packages/skia/src/skia/web/JsiSkImageFactory.ts index cfedc81682..e00ce81774 100644 --- a/packages/skia/src/skia/web/JsiSkImageFactory.ts +++ b/packages/skia/src/skia/web/JsiSkImageFactory.ts @@ -102,11 +102,11 @@ export class JsiSkImageFactory extends Host implements ImageFactory { return new JsiSkImage(this.CanvasKit, image); } - MakeImageFromTexture(_texture: GPUTexture): SkImage { + MakeImageFromNativeTexture(_pointer: bigint): SkImage { return throwNotImplementedOnRNWeb(); } - MakeTextureFromImage(_image: SkImage): GPUTexture { - return throwNotImplementedOnRNWeb(); + MakeNativeTextureFromImage(_image: SkImage): bigint { + return throwNotImplementedOnRNWeb(); } } diff --git a/packages/skia/src/skia/web/JsiSkia.ts b/packages/skia/src/skia/web/JsiSkia.ts index af62495e99..d17d952541 100644 --- a/packages/skia/src/skia/web/JsiSkia.ts +++ b/packages/skia/src/skia/web/JsiSkia.ts @@ -143,10 +143,7 @@ export const JsiSkApi = (CanvasKit: CanvasKit): Skia => ({ Recorder: () => { return throwNotImplementedOnRNWeb(); }, - getDevice: () => { - return throwNotImplementedOnRNWeb(); - }, - hasDevice: () => { - return false; + getNativeDevice: () => { + return throwNotImplementedOnRNWeb(); }, }); diff --git a/packages/skia/src/specs/WebGPUViewNativeComponent.ts b/packages/skia/src/specs/WebGPUViewNativeComponent.ts deleted file mode 100644 index fbb9979afd..0000000000 --- a/packages/skia/src/specs/WebGPUViewNativeComponent.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { codegenNativeComponent } from "react-native"; -import type { ViewProps } from "react-native"; -import type { Int32 } from "react-native/Libraries/Types/CodegenTypes"; - -export interface NativeProps extends ViewProps { - contextId: Int32; - transparent: boolean; -} - -// eslint-disable-next-line import/no-default-export -export default codegenNativeComponent("SkiaWebGPUView"); diff --git a/packages/skia/src/specs/WebGPUViewNativeComponent.web.ts b/packages/skia/src/specs/WebGPUViewNativeComponent.web.ts deleted file mode 100644 index 8bc962dbca..0000000000 --- a/packages/skia/src/specs/WebGPUViewNativeComponent.web.ts +++ /dev/null @@ -1,110 +0,0 @@ -import React, { useEffect, useRef } from "react"; -import { StyleSheet } from "react-native"; -import type { Int32 } from "react-native/Libraries/Types/CodegenTypes"; -import type { ViewProps } from "react-native"; - -import { contextIdToId } from "./utils"; - -export interface NativeProps extends ViewProps { - contextId: Int32; - transparent: boolean; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function debounce void>( - func: T, - wait: number, - immediate = false -) { - let timeout: ReturnType | undefined; - return function debounced( - this: ThisParameterType, - ...args: Parameters - ) { - const context = this; - const callNow = immediate && !timeout; - if (timeout) { - clearTimeout(timeout); - } - timeout = setTimeout(() => { - timeout = undefined; - if (!immediate) { - func.apply(context, args); - } - }, wait); - if (callNow) { - func.apply(context, args); - } - }; -} - -function resizeCanvas(canvas: HTMLCanvasElement | null) { - if (!canvas) { - return; - } - - const dpr = window.devicePixelRatio || 1; - - const { height, width } = canvas.getBoundingClientRect(); - canvas.setAttribute("height", (height * dpr).toString()); - canvas.setAttribute("width", (width * dpr).toString()); -} - -// eslint-disable-next-line import/no-default-export -export default function WebGPUViewNativeComponent( - props: NativeProps -): React.JSX.Element { - const { contextId, style, transparent, ...rest } = props; - - const canvasElm = useRef(null); - - useEffect(() => { - const onResize = debounce(() => resizeCanvas(canvasElm.current), 100); - window.addEventListener("resize", onResize); - return () => { - window.removeEventListener("resize", onResize); - }; - }, []); - - return React.createElement("canvas", { - ...rest, - id: contextIdToId(contextId), - style: { - ...styles.view, - ...styles.flex1, - ...(transparent === false ? { backgroundColor: "white" } : {}), - ...(typeof style === "object" ? style : {}), - }, - ref: (ref: HTMLCanvasElement) => { - canvasElm.current = ref; - if (ref) { - resizeCanvas(ref); - } - }, - }); -} - -const styles = StyleSheet.create({ - flex1: { - flex: 1, - }, - view: { - alignItems: "stretch", - backgroundColor: "transparent", - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - border: "0 solid black", - boxSizing: "border-box", - display: "flex", - flexBasis: "auto", - flexDirection: "column", - flexShrink: 0, - listStyle: "none", - margin: 0, - minHeight: 0, - minWidth: 0, - padding: 0, - position: "relative", - zIndex: 0, - }, -}); diff --git a/packages/skia/src/specs/utils.ts b/packages/skia/src/specs/utils.ts deleted file mode 100644 index 39fa1b8df9..0000000000 --- a/packages/skia/src/specs/utils.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Only used on the web -export function contextIdToId(contextId: number) { - return "rnwgpu-canvas-" + contextId; -} diff --git a/packages/skia/src/views/WebGPUCanvas.tsx b/packages/skia/src/views/WebGPUCanvas.tsx deleted file mode 100644 index 024bdd3dbe..0000000000 --- a/packages/skia/src/views/WebGPUCanvas.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import React, { useEffect, useImperativeHandle, useRef, useState } from "react"; -import type { ViewProps } from "react-native"; -import { View, Platform } from "react-native"; - -import WebGPUNativeView from "../specs/WebGPUViewNativeComponent"; - -let CONTEXT_COUNTER = 1; -function generateContextId() { - return CONTEXT_COUNTER++; -} - -declare global { - var RNWebGPU: { - gpu: GPU; - fabric: boolean; - getNativeSurface: (contextId: number) => NativeCanvas; - MakeWebGPUCanvasContext: ( - contextId: number, - width: number, - height: number - ) => RNCanvasContext; - // Retires a canvas context; called by the Canvas on unmount (the Canvas - // owns the native registry entry for its contextId). - destroyContext: (contextId: number) => void; - }; -} - -type SurfacePointer = bigint; - -export interface NativeCanvas { - surface: SurfacePointer; - width: number; - height: number; - clientWidth: number; - clientHeight: number; -} - -export type RNCanvasContext = GPUCanvasContext & { - present: () => void; -}; - -export interface WebGPUCanvasRef { - getContextId: () => number; - getContext(contextName: "webgpu"): RNCanvasContext | null; - getNativeSurface: () => NativeCanvas; -} - -interface WebGPUCanvasProps extends ViewProps { - transparent?: boolean; - ref?: React.Ref; -} - -export const WebGPUCanvas = ({ - transparent, - ref, - ...props -}: WebGPUCanvasProps) => { - const viewRef = useRef(null); - const [contextId] = useState(() => generateContextId()); - - // Retire the native registry entry for this contextId on unmount. When a - // native surface is still attached, this is a no-op and the native view's - // own teardown retires the entry instead — which keeps StrictMode's - // simulated unmount (which re-runs effects without unmounting native views) - // from orphaning a live surface. - useEffect(() => { - return () => { - if (typeof RNWebGPU !== "undefined") { - RNWebGPU.destroyContext(contextId); - } - }; - }, [contextId]); - - useImperativeHandle(ref, () => ({ - getContextId: () => contextId, - getNativeSurface: () => { - if (typeof RNWebGPU === "undefined") { - throw new Error( - "[WebGPU] RNWebGPU is not available. Make sure SK_GRAPHITE is enabled." - ); - } - return RNWebGPU.getNativeSurface(contextId); - }, - getContext(contextName: "webgpu"): RNCanvasContext | null { - if (contextName !== "webgpu") { - throw new Error(`[WebGPU] Unsupported context: ${contextName}`); - } - if (!viewRef.current) { - throw new Error("[WebGPU] Cannot get context before mount"); - } - if (typeof RNWebGPU === "undefined") { - throw new Error( - "[WebGPU] RNWebGPU is not available. Make sure SK_GRAPHITE is enabled." - ); - } - // getBoundingClientRect became stable in RN 0.83 - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const view = viewRef.current as any; - const size = - "getBoundingClientRect" in view - ? view.getBoundingClientRect() - : view.unstable_getBoundingClientRect(); - return RNWebGPU.MakeWebGPUCanvasContext( - contextId, - size.width, - size.height - ); - }, - })); - - // WebGPU Canvas is not supported on web - if (Platform.OS === "web") { - return ; - } - - return ( - - - - ); -}; diff --git a/packages/skia/src/views/WebGPUCanvas.web.tsx b/packages/skia/src/views/WebGPUCanvas.web.tsx deleted file mode 100644 index feed4e559b..0000000000 --- a/packages/skia/src/views/WebGPUCanvas.web.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import type { ViewProps } from "react-native"; - -export interface NativeCanvas { - surface: bigint; - width: number; - height: number; - clientWidth: number; - clientHeight: number; -} - -export type RNCanvasContext = GPUCanvasContext & { - present: () => void; -}; - -export interface WebGPUCanvasRef { - getContextId: () => number; - getContext(contextName: "webgpu"): RNCanvasContext | null; - getNativeSurface: () => NativeCanvas; -} - -interface WebGPUCanvasProps extends ViewProps { - transparent?: boolean; - ref?: React.Ref; -} - -// WebGPU Canvas is not supported on web -export const WebGPUCanvas = ({ - transparent: _transparent, - ref: _ref, - ...props -}: WebGPUCanvasProps) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - return
; -}; diff --git a/packages/skia/src/views/index.ts b/packages/skia/src/views/index.ts index 618dc1103e..bbc87afa6c 100644 --- a/packages/skia/src/views/index.ts +++ b/packages/skia/src/views/index.ts @@ -1,4 +1,3 @@ export * from "./SkiaPictureView"; export * from "./types"; -export * from "./WebGPUCanvas"; export * from "./formats"; diff --git a/yarn.lock b/yarn.lock index 6ed70b0621..c50981f4d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16339,6 +16339,7 @@ __metadata: react-native-svg: "patch:react-native-svg@npm%3A15.14.0#../../.yarn/patches/react-native-svg-npm-15.14.0-macos-uiimage-fix.patch" react-native-test-app: 4.4.7 react-native-web: ^0.21.2 + react-native-webgpu: 0.8.0 react-native-windows: ^0.75.0 react-native-worklets: 0.8.3 react-test-renderer: 19.0.0 @@ -27336,6 +27337,23 @@ __metadata: languageName: node linkType: hard +"react-native-webgpu@npm:0.8.0": + version: 0.8.0 + resolution: "react-native-webgpu@npm:0.8.0" + peerDependencies: + react: "*" + react-native: ">=0.81.0" + react-native-reanimated: ">=4.2.1" + react-native-worklets: ">=0.7.2" + peerDependenciesMeta: + react-native-reanimated: + optional: true + react-native-worklets: + optional: true + checksum: 75a850ebf19d57395ca1b4ba7d4f6f24ff203e047c99493d1a3d4fbb4bbb08308a573ead0e2c88ef5de367d355e576d181b9513fb6cec93ab77e548211976c0c + languageName: node + linkType: hard + "react-native-windows@npm:^0.75.0": version: 0.75.20 resolution: "react-native-windows@npm:0.75.20" From 289d31b89caf08bc7547bd0be322f1818bdf6c5d Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 29 Jul 2026 12:57:41 +0200 Subject: [PATCH 2/3] =?UTF-8?q?chore(=F0=9F=92=84):=20remove=20fork=20work?= =?UTF-8?q?flows=20(#3982)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/wcandillon-ci-graphite.yml | 253 --------- .github/workflows/wcandillon-ci.yml | 385 -------------- .github/workflows/wcandillon-test-package.yml | 92 ---- .../wcandillon-test-skia-package.yml | 500 ------------------ .github/workflows/wcandillon-test-windows.yml | 24 - 5 files changed, 1254 deletions(-) delete mode 100644 .github/workflows/wcandillon-ci-graphite.yml delete mode 100644 .github/workflows/wcandillon-ci.yml delete mode 100644 .github/workflows/wcandillon-test-package.yml delete mode 100644 .github/workflows/wcandillon-test-skia-package.yml delete mode 100644 .github/workflows/wcandillon-test-windows.yml diff --git a/.github/workflows/wcandillon-ci-graphite.yml b/.github/workflows/wcandillon-ci-graphite.yml deleted file mode 100644 index 1268b6eb95..0000000000 --- a/.github/workflows/wcandillon-ci-graphite.yml +++ /dev/null @@ -1,253 +0,0 @@ -# OWNER: wcandillon/react-native-skia -# RUNNER: the iOS Graphite job runs on the self-hosted macOS runner; the -# Android Graphite jobs stay on GitHub-hosted Ubuntu runners. -name: wcandillon - CI Graphite -on: - push: - branches: - - main - - next - pull_request: - branches: - - main - - next - merge_group: - types: - - checks_requested - -concurrency: - group: wcandillon-${{ github.ref }}-graphite - cancel-in-progress: true - -jobs: - build-android-graphite: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: ubuntu-latest - env: - TURBO_CACHE_DIR: .turbo/android - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - graphite: true - - - name: Free disk space - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - with: - tool-cache: false - android: false - dotnet: true - haskell: true - large-packages: true - docker-images: true - swap-storage: true - - - name: Cache turborepo for Android - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-android - - - name: Install JDK - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 - with: - distribution: 'zulu' - java-version: '17' - - - name: Install NDK - uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0 - id: setup-ndk - with: - ndk-version: r27d - - - name: Set ANDROID_NDK - run: echo "ANDROID_NDK=$ANDROID_HOME/ndk-bundle" >> $GITHUB_ENV - - - name: Finalize Android SDK - run: | - /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" - - - name: Install Android SDK - run: | - echo "sdk.dir=$ANDROID_HOME" > $GITHUB_WORKSPACE/apps/example/android/local.properties - - - name: Cache Gradle - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('./apps/example/android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - - name: Build example for Android - env: - JAVA_OPTS: "-XX:MaxHeapSize=6g" - run: | - yarn turbo run build:android --concurrency 1 - - - name: Cache apk - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - env: - cache-name: cache-apk - with: - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - key: apk-graphite-${{ github.sha }} - - - name: Upload Android APK artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: android-example-apk-graphite - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - - test-android-graphite: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - needs: build-android-graphite - runs-on: ubuntu-latest - timeout-minutes: 60 - env: - TURBO_CACHE_DIR: .turbo/android - steps: - - name: checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - graphite: true - - - name: Setup Android SDK - uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1 - - - name: Install Android SDK tools - run: | - echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV - echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH - echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH - echo "$ANDROID_HOME/emulator" >> $GITHUB_PATH - - - name: Enable KVM group perms - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Restore APK - id: cache-apk - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - key: apk-graphite-${{ github.sha }} - - - name: Start Package Manager - working-directory: apps/example/ - run: E2E=true yarn start & - - - name: Run Android Emulator Tests - uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0 - with: - api-level: 30 - arch: x86_64 - profile: Nexus 5X - force-avd-creation: true - emulator-options: -no-snapshot-save -no-window -gpu swangle_indirect -noaudio -no-boot-anim - disable-animations: true - script: | - # Wait for Metro bundler - sleep 10 - - # Install and launch app - adb install -r apps/example/android/app/build/outputs/apk/debug/app-debug.apk - adb shell monkey -p com.microsoft.reacttestapp 1 - - # Run tests - # On Graphite we run the Path render tests plus the WebGPU specs. - # ArrayBuffer, ComputeShader, ErrorScope, ImageBitmapBounds and - # DawnToggles are pure surface.eval round-trips that assert on - # returned values. The external-texture specs (ExternalTexture, - # ImportExternalTexture, SharedTextureMemory) additionally exercise - # NativeBuffer import and GPU read-back; they self-validate via - # copyTextureToBuffer (not Skia image readPixels) and skip - # themselves where NativeBuffer/createImageBitmap are unavailable. - cd packages/skia && CI=true yarn test -i "e2e/(Path|ArrayBuffer|ComputeShader|ErrorScope|ImageBitmapBounds|DawnToggles|ExternalTexture|ImportExternalTexture|SharedTextureMemory)" --testPathIgnorePatterns Paragraphs - - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - if: failure() - with: - path: packages/skia/src/__tests__/snapshots/ - name: tests-snapshots-screenshots - - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - if: failure() - with: - path: apps/docs/static/ - name: tests-docs-screenshots - - build-test-ios-graphite: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: [self-hosted, macOS] - env: - TURBO_CACHE_DIR: .turbo/ios - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - graphite: true - - - name: Cache turborepo for iOS - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-ios- - - - name: Check turborepo cache for iOS - run: | - TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir=\"${{ env.TURBO_CACHE_DIR }}\" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status") - - if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then - echo "turbo_cache_hit=1" >> $GITHUB_ENV - fi - - - name: Install CocoaPods - working-directory: apps/example/ios - run: pod install - - - name: Start Package Manager - working-directory: apps/example - run: E2E=true yarn start & - - - name: Build example for iOS - working-directory: apps/example - run: yarn ios --simulator 'iPhone 16 Pro' - - - name: Run e2e tests - working-directory: packages/skia - # On Graphite we run the Paths render test plus the WebGPU specs. - # ArrayBuffer, ComputeShader, ErrorScope, ImageBitmapBounds and - # DawnToggles are pure surface.eval round-trips that assert on returned - # values. The external-texture specs (ExternalTexture, - # ImportExternalTexture, SharedTextureMemory) additionally exercise - # NativeBuffer import and GPU read-back; they self-validate via - # copyTextureToBuffer (not Skia image readPixels) and skip themselves - # where NativeBuffer/createImageBitmap are unavailable. - run: CI=true E2E=true yarn test -i "e2e/(Paths|ArrayBuffer|ComputeShader|ErrorScope|ImageBitmapBounds|DawnToggles|ExternalTexture|ImportExternalTexture|SharedTextureMemory)" diff --git a/.github/workflows/wcandillon-ci.yml b/.github/workflows/wcandillon-ci.yml deleted file mode 100644 index 5a49f8db07..0000000000 --- a/.github/workflows/wcandillon-ci.yml +++ /dev/null @@ -1,385 +0,0 @@ -# OWNER: wcandillon/react-native-skia -# RUNNER: macOS jobs (test, build-test-ios, build-test-macos) run on the -# self-hosted macOS runner; they serialize naturally since there is a single -# runner. Ubuntu jobs stay on GitHub-hosted runners. -# NOTE: Windows build and package e2e tests are intentionally NOT part of this -# automatic CI - they are dispatched manually (see dedicated workflows). -name: wcandillon - CI -on: - push: - branches: - - main - - next - pull_request: - branches: - - main - - next - merge_group: - types: - - checks_requested - -concurrency: - group: wcandillon-${{ github.ref }} - cancel-in-progress: true - -jobs: - lint: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - - run: pip install cpplint - - run: cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=package/cpp/skia --exclude=package/apple --exclude=package/android/build --exclude=package/node_modules --recursive package - - - name: Install clang-format - run: sudo apt-get update && sudo apt-get install -y clang-format-18 - - - name: Lint files - run: yarn lint - - - name: Typecheck files - run: yarn tsc - - test: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: [self-hosted, macOS] - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Test - run: yarn test - - test-web: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: [self-hosted, macOS] - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Playwright Chromium - run: yarn playwright install chromium - - - name: Free Metro port - run: lsof -ti :8081 | xargs kill -9 || true - - - name: Run web example tests - run: yarn test:web - - - name: Upload screenshots - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: web-example-screenshots - path: apps/example/e2e/screenshots/ - if-no-files-found: ignore - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: web-example-test-results - path: apps/example/test-results/ - if-no-files-found: ignore - - build-library: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: ubuntu-latest - outputs: - run_id: ${{ github.run_id }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build package - run: yarn build - - - name: Pack package - working-directory: packages/skia - run: yarn pack - - - name: Upload package artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: package-tgz - path: packages/skia/package.tgz - - - name: Build dry run release - working-directory: packages/skia - run: | - npx semantic-release --dry-run - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - build-android: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: ubuntu-latest - env: - TURBO_CACHE_DIR: .turbo/android - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Free disk space - run: | - echo "Disk usage before cleanup:" - df -h - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo docker image prune -af || true - sudo apt-get clean - echo "Disk usage after cleanup:" - df -h - - - name: Cache turborepo for Android - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-android - - - name: Install JDK - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 - with: - distribution: 'zulu' - java-version: '17' - - - name: Install NDK - uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0 - id: setup-ndk - with: - ndk-version: r27d - - - name: Set ANDROID_NDK - run: echo "ANDROID_NDK=$ANDROID_HOME/ndk-bundle" >> $GITHUB_ENV - - - name: Finalize Android SDK - run: | - /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" - - - name: Install Android SDK - run: | - echo "sdk.dir=$ANDROID_HOME" > $GITHUB_WORKSPACE/apps/example/android/local.properties - - - name: Cache Gradle - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - ~/.gradle/wrapper - ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('./apps/example/android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - - name: Build example for Android - env: - JAVA_OPTS: "-XX:MaxHeapSize=6g" - run: | - yarn turbo run build:android --concurrency 1 - - - name: Cache apk - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - env: - cache-name: cache-apk - with: - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - key: apk-${{ github.sha }} - - - name: Upload Android APK artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: android-example-apk - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - - test-android: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - needs: build-android - runs-on: ubuntu-latest - timeout-minutes: 60 - env: - TURBO_CACHE_DIR: .turbo/android - steps: - - name: checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Android SDK - uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1 - - - name: Install Android SDK tools - run: | - echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV - echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH - echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH - echo "$ANDROID_HOME/emulator" >> $GITHUB_PATH - - - name: Enable KVM group perms - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Restore APK - id: cache-apk - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: apps/example/android/app/build/outputs/apk/debug/app-debug.apk - key: apk-${{ github.sha }} - - - name: Start Package Manager - working-directory: apps/example/ - run: E2E=true yarn start & - - - name: Run Android Emulator Tests - uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0 - with: - api-level: 30 - arch: x86_64 - profile: Nexus 5X - force-avd-creation: true - emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim - disable-animations: true - script: | - # Wait for Metro bundler - sleep 10 - - # Install and launch app - adb install -r apps/example/android/app/build/outputs/apk/debug/app-debug.apk - adb shell monkey -p com.microsoft.reacttestapp 1 - - # Run tests - cd packages/skia && CI=true yarn e2e --testPathIgnorePatterns Paragraphs - - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - if: failure() - with: - path: packages/skia/src/__tests__/snapshots/ - name: tests-snapshots-screenshots - - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - if: failure() - with: - path: apps/docs/static/ - name: tests-docs-screenshots - - build-test-ios: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: [self-hosted, macOS] - env: - TURBO_CACHE_DIR: .turbo/ios - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Cache turborepo for iOS - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-ios- - - - name: Check turborepo cache for iOS - run: | - TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status") - - if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then - echo "turbo_cache_hit=1" >> $GITHUB_ENV - fi - - - name: Install CocoaPods - working-directory: apps/example/ios - run: pod install - - - name: Start Package Manager - working-directory: apps/example - run: E2E=true yarn start & - - - name: Build example for iOS - working-directory: apps/example - run: yarn ios --simulator 'iPhone 16 Pro' - - - name: Run e2e tests - working-directory: packages/skia - run: CI=true yarn e2e - - build-test-macos: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: [self-hosted, macOS] - env: - TURBO_CACHE_DIR: .turbo/macos - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Cache turborepo for macOS - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ${{ env.TURBO_CACHE_DIR }} - key: ${{ runner.os }}-turborepo-macos-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-turborepo-macos- - - - name: Build example for macOS - run: yarn turbo run build:macos --concurrency 1 diff --git a/.github/workflows/wcandillon-test-package.yml b/.github/workflows/wcandillon-test-package.yml deleted file mode 100644 index 4b048b32b4..0000000000 --- a/.github/workflows/wcandillon-test-package.yml +++ /dev/null @@ -1,92 +0,0 @@ -# OWNER: wcandillon/react-native-skia -# Manual-dispatch package e2e test: builds the package from the current branch, -# then installs the resulting .tgz into a fresh Expo app and runs it on -# iOS / Android / Web. Mirrors the test-package-e2e jobs that used to live in -# CI. The macOS test jobs run on GitHub-hosted runners (see -# wcandillon-test-skia-package.yml). -name: wcandillon - Test Package -on: - workflow_dispatch: - inputs: - test_ios: - description: 'Run iOS tests' - required: false - type: boolean - default: true - test_android: - description: 'Run Android tests' - required: false - type: boolean - default: true - test_web: - description: 'Run Web tests' - required: false - type: boolean - default: true - ios_use_frameworks: - description: 'iOS framework linkage' - required: false - type: choice - options: - - dynamic - - static - default: dynamic - simulator_device: - description: 'iOS Simulator device' - required: false - default: 'iPhone 16 Pro' - type: string - android_api_level: - description: 'Android API level' - required: false - default: '30' - type: string - android_device: - description: 'Android device profile' - required: false - default: 'Nexus 5X' - type: string - -jobs: - build-library: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: ubuntu-latest - outputs: - run_id: ${{ github.run_id }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build package - run: yarn build - - - name: Pack package - working-directory: packages/skia - run: yarn pack - - - name: Upload package artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0.0 - with: - name: package-tgz - path: packages/skia/package.tgz - - test-package-e2e: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - needs: build-library - uses: ./.github/workflows/wcandillon-test-skia-package.yml - with: - skia_version: artifact:${{ needs.build-library.outputs.run_id }} - test_ios: ${{ inputs.test_ios }} - test_android: ${{ inputs.test_android }} - test_web: ${{ inputs.test_web }} - ios_use_frameworks: ${{ inputs.ios_use_frameworks }} - simulator_device: ${{ inputs.simulator_device }} - android_api_level: ${{ inputs.android_api_level }} - android_device: ${{ inputs.android_device }} diff --git a/.github/workflows/wcandillon-test-skia-package.yml b/.github/workflows/wcandillon-test-skia-package.yml deleted file mode 100644 index 79ae4160a5..0000000000 --- a/.github/workflows/wcandillon-test-skia-package.yml +++ /dev/null @@ -1,500 +0,0 @@ -# OWNER: wcandillon/react-native-skia -# Fork copy of test-skia-package.yml. Only difference: the package artifact is -# downloaded from the calling repository (github.repository) instead of being -# hardcoded to Shopify/react-native-skia. Jobs run on GitHub-hosted macOS. -name: wcandillon - Test Skia Package (Reusable) - -on: - workflow_call: - inputs: - skia_version: - description: 'Skia version to test (version number, "latest", URL to .tgz, or "artifact:RUN_ID")' - required: true - type: string - test_ios: - description: 'Run iOS tests' - required: false - type: boolean - default: true - test_android: - description: 'Run Android tests' - required: false - type: boolean - default: true - simulator_device: - description: 'iOS Simulator device' - required: false - default: 'iPhone 16 Pro' - type: string - android_api_level: - description: 'Android API level' - required: false - default: '30' - type: string - android_device: - description: 'Android device profile' - required: false - default: 'Nexus 5X' - type: string - test_web: - description: 'Run Web tests' - required: false - type: boolean - default: true - ios_use_frameworks: - description: 'iOS framework linkage: "dynamic" (default) or "static"' - required: false - type: string - default: 'dynamic' - -jobs: - test-skia-ios: - if: inputs.test_ios - runs-on: macos-latest-xlarge - timeout-minutes: 30 - - steps: - - name: Checkout repository - uses: actions/checkout@v7.0.1 - - - name: Setup Node.js - uses: actions/setup-node@v7.0.0 - with: - node-version-file: .nvmrc - - - name: Setup Yarn - run: | - corepack enable - yarn --version - - - name: Select latest Xcode - run: | - LATEST_XCODE=$(ls -d /Applications/Xcode_*.app | sort -V | tail -n 1) - echo "Selecting: $LATEST_XCODE" - sudo xcode-select -s "$LATEST_XCODE/Contents/Developer" - xcodebuild -version - swift --version - - - name: List available simulators - run: xcrun simctl list devices - - - name: Create test directory - run: | - mkdir -p /Users/runner/skia-test-app - cd /Users/runner/skia-test-app - pwd - - - name: Create Expo app with Skia template - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 120 - command: | - cd /Users/runner/skia-test-app - echo "Creating Expo app with Skia template..." - yarn create expo-app my-app -e with-skia - - - name: Download artifact package if specified - if: startsWith(inputs.skia_version, 'artifact:') - run: | - ARTIFACT_ID=$(echo "${{ inputs.skia_version }}" | sed 's/artifact://') - echo "Downloading artifact ID: $ARTIFACT_ID" - gh run download --repo ${{ github.repository }} $ARTIFACT_ID -n package-tgz -D /tmp - env: - GH_TOKEN: ${{ github.token }} - - - name: Install React Native Skia - working-directory: /Users/runner/skia-test-app/my-app - run: | - VERSION="${{ inputs.skia_version }}" - if [ "$VERSION" == "latest" ]; then - echo "Installing @shopify/react-native-skia@latest..." - yarn add @shopify/react-native-skia@latest - elif [[ "$VERSION" == artifact:* ]]; then - echo "Installing @shopify/react-native-skia from downloaded artifact..." - yarn add @shopify/react-native-skia@file:/tmp/package.tgz - elif [[ "$VERSION" == http* ]]; then - echo "Installing @shopify/react-native-skia from URL: $VERSION" - yarn add @shopify/react-native-skia@"$VERSION" - else - echo "Installing @shopify/react-native-skia@$VERSION..." - yarn add @shopify/react-native-skia@"$VERSION" - fi - - - name: Show installed Skia version - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installed React Native Skia version:" - yarn list @shopify/react-native-skia --depth=0 - - - name: Install TypeScript dependencies - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing TypeScript dependencies..." - yarn expo install typescript @types/react - - - name: Install Expo Dev Client - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing expo-dev-client..." - yarn expo install expo-dev-client - - - name: Enable static frameworks (iOS) - if: inputs.ios_use_frameworks == 'static' - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Configuring expo-build-properties for useFrameworks: 'static'..." - yarn expo install expo-build-properties - node -e " - const fs = require('fs'); - const cfg = JSON.parse(fs.readFileSync('app.json', 'utf8')); - cfg.expo.plugins = cfg.expo.plugins || []; - cfg.expo.plugins.push(['expo-build-properties', { ios: { useFrameworks: 'static' } }]); - fs.writeFileSync('app.json', JSON.stringify(cfg, null, 2)); - " - - - name: Prebuild native directories - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Generating native iOS directory (linkage: ${{ inputs.ios_use_frameworks }})..." - yarn expo prebuild --platform ios - - - name: Install iOS dependencies - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing iOS dependencies..." - cd ios - pod install --repo-update - - - name: Start Metro bundler - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Starting Metro bundler in background..." - yarn expo start --dev-client & - sleep 10 - - - name: Build and run iOS app - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Building and running iOS app on simulator: ${{ inputs.simulator_device }}..." - yarn expo run:ios --device "${{ inputs.simulator_device }}" - - - name: Wait for app to launch - run: | - echo "Waiting for app to launch and stabilize..." - sleep 30 - - - name: Capture simulator screenshot - if: always() - run: | - SIMULATOR_ID=$(xcrun simctl list devices | grep "${{ inputs.simulator_device }}" | grep -E 'Booted' | head -n 1 | cut -d '(' -f 2 | cut -d ')' -f 1) - if [ -n "$SIMULATOR_ID" ]; then - echo "Capturing screenshot from simulator ID: $SIMULATOR_ID" - xcrun simctl io $SIMULATOR_ID screenshot /Users/runner/skia-test-screenshot-ios.png - else - echo "No booted simulator found" - fi - - - name: Upload screenshot - if: always() - uses: actions/upload-artifact@v7 - with: - name: ios-simulator-screenshot-${{ github.run_id }} - path: /Users/runner/skia-test-screenshot-ios.png - if-no-files-found: ignore - - - name: Print test summary - if: always() - run: | - echo "================================================================" - echo "iOS Test Summary:" - echo "================================================================" - echo "✓ Created Expo app with Skia template" - echo "✓ Installed @shopify/react-native-skia@${{ inputs.skia_version }}" - echo "✓ Installed expo-dev-client" - echo "✓ Framework linkage: ${{ inputs.ios_use_frameworks }}" - echo "✓ Built and ran iOS app on ${{ inputs.simulator_device }}" - echo "================================================================" - - test-skia-android: - if: inputs.test_android - runs-on: macos-latest-large - timeout-minutes: 60 - - steps: - - name: Checkout repository - uses: actions/checkout@v7.0.1 - - - name: Setup Node.js - uses: actions/setup-node@v7.0.0 - with: - node-version-file: .nvmrc - - - name: Setup Yarn - run: | - corepack enable - yarn --version - - - name: Setup Java - uses: actions/setup-java@v5 - with: - distribution: 'zulu' - java-version: '17' - - - name: Download Android system image - run: $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-${{ inputs.android_api_level }};default;x86_64" - - - name: Create Android emulator - run: | - echo "Creating Android emulator..." - $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n test_avd --device '${{ inputs.android_device }}' --package "system-images;android-${{ inputs.android_api_level }};default;x86_64" --sdcard 512M --force - - - name: Create test directory - run: | - mkdir -p /Users/runner/skia-test-app - cd /Users/runner/skia-test-app - pwd - - - name: Create Expo app with Skia template - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 120 - command: | - cd /Users/runner/skia-test-app - echo "Creating Expo app with Skia template..." - yarn create expo-app my-app -e with-skia - - - name: Download artifact package if specified - if: startsWith(inputs.skia_version, 'artifact:') - run: | - ARTIFACT_ID=$(echo "${{ inputs.skia_version }}" | sed 's/artifact://') - echo "Downloading artifact ID: $ARTIFACT_ID" - gh run download --repo ${{ github.repository }} $ARTIFACT_ID -n package-tgz -D /tmp - env: - GH_TOKEN: ${{ github.token }} - - - name: Install React Native Skia - working-directory: /Users/runner/skia-test-app/my-app - run: | - VERSION="${{ inputs.skia_version }}" - if [ "$VERSION" == "latest" ]; then - echo "Installing @shopify/react-native-skia@latest..." - yarn add @shopify/react-native-skia@latest - elif [[ "$VERSION" == artifact:* ]]; then - echo "Installing @shopify/react-native-skia from downloaded artifact..." - yarn add @shopify/react-native-skia@file:/tmp/package.tgz - elif [[ "$VERSION" == http* ]]; then - echo "Installing @shopify/react-native-skia from URL: $VERSION" - yarn add @shopify/react-native-skia@"$VERSION" - else - echo "Installing @shopify/react-native-skia@$VERSION..." - yarn add @shopify/react-native-skia@"$VERSION" - fi - - - name: Show installed Skia version - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installed React Native Skia version:" - yarn list @shopify/react-native-skia --depth=0 - - - name: Install TypeScript dependencies - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing TypeScript dependencies..." - yarn expo install typescript @types/react - - - name: Install Expo Dev Client - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing expo-dev-client..." - yarn expo install expo-dev-client - - - name: Prebuild native directories - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Generating native Android directory..." - yarn expo prebuild --platform android - - - name: Start Android emulator - run: | - echo "Starting Android emulator in background..." - $ANDROID_HOME/emulator/emulator -memory 4096 -avd test_avd -wipe-data -no-window -gpu angle_indirect -no-snapshot -noaudio -no-boot-anim & - - - name: Wait for emulator to boot - run: | - echo "Waiting for Android emulator to boot..." - adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;' - echo "Emulator is ready" - adb devices - timeout-minutes: 10 - - - name: Start Metro bundler - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Starting Metro bundler in background..." - yarn expo start --dev-client & - sleep 10 - - - name: Build and run Android app - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Building and running Android app on emulator..." - yarn expo run:android - - - name: Wait for app to launch - run: | - echo "Waiting for app to launch and stabilize..." - sleep 120 - - - name: Capture emulator screenshot - if: always() - run: | - echo "Capturing screenshot from Android emulator..." - adb exec-out screencap -p > /Users/runner/skia-test-screenshot-android.png || echo "Failed to capture screenshot" - - - name: Upload screenshot - if: always() - uses: actions/upload-artifact@v7 - with: - name: android-emulator-screenshot-${{ github.run_id }} - path: /Users/runner/skia-test-screenshot-android.png - if-no-files-found: ignore - - - name: Print test summary - if: always() - run: | - echo "================================================================" - echo "Android Test Summary:" - echo "================================================================" - echo "✓ Created Expo app with Skia template" - echo "✓ Installed @shopify/react-native-skia@${{ inputs.skia_version }}" - echo "✓ Installed expo-dev-client" - echo "✓ Built and ran Android app on API level ${{ inputs.android_api_level }}" - echo "================================================================" - - test-skia-web: - if: inputs.test_web - runs-on: macos-latest-large - timeout-minutes: 30 - - steps: - - name: Checkout repository - uses: actions/checkout@v7.0.1 - - - name: Setup Node.js - uses: actions/setup-node@v7.0.0 - with: - node-version-file: .nvmrc - - - name: Setup Yarn - run: | - corepack enable - yarn --version - - - name: Create test directory - run: | - mkdir -p /Users/runner/skia-test-app - cd /Users/runner/skia-test-app - pwd - - - name: Create Expo app with Skia template - uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 - with: - timeout_minutes: 10 - max_attempts: 3 - retry_wait_seconds: 120 - command: | - cd /Users/runner/skia-test-app - echo "Creating Expo app with Skia template..." - yarn create expo-app my-app -e with-skia - - - name: Download artifact package if specified - if: startsWith(inputs.skia_version, 'artifact:') - run: | - ARTIFACT_ID=$(echo "${{ inputs.skia_version }}" | sed 's/artifact://') - echo "Downloading artifact ID: $ARTIFACT_ID" - gh run download --repo ${{ github.repository }} $ARTIFACT_ID -n package-tgz -D /tmp - env: - GH_TOKEN: ${{ github.token }} - - - name: Install React Native Skia - working-directory: /Users/runner/skia-test-app/my-app - run: | - VERSION="${{ inputs.skia_version }}" - if [ "$VERSION" == "latest" ]; then - echo "Installing @shopify/react-native-skia@latest..." - yarn add @shopify/react-native-skia@latest - elif [[ "$VERSION" == artifact:* ]]; then - echo "Installing @shopify/react-native-skia from downloaded artifact..." - yarn add @shopify/react-native-skia@file:/tmp/package.tgz - elif [[ "$VERSION" == http* ]]; then - echo "Installing @shopify/react-native-skia from URL: $VERSION" - yarn add @shopify/react-native-skia@"$VERSION" - else - echo "Installing @shopify/react-native-skia@$VERSION..." - yarn add @shopify/react-native-skia@"$VERSION" - fi - - - name: Show installed Skia version - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installed React Native Skia version:" - yarn list @shopify/react-native-skia --depth=0 - - - name: Install TypeScript dependencies - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Installing TypeScript dependencies..." - yarn expo install typescript @types/react - - - name: Install repo dependencies for Playwright - run: yarn install --immutable - - - name: Install Playwright dependencies - run: | - echo "Installing Playwright..." - yarn playwright install chromium - yarn playwright install-deps chromium - - - name: Start web server - working-directory: /Users/runner/skia-test-app/my-app - run: | - echo "Starting web server in background..." - yarn expo start --web & - sleep 30 - - - name: Wait for web app to be ready - run: | - echo "Waiting for web app to be accessible..." - timeout 60 bash -c 'until curl -s http://localhost:8081 > /dev/null; do sleep 2; done' || echo "Web server may not be fully ready" - echo "Waiting additional time for app to fully render..." - sleep 30 - - - name: Take screenshot - if: always() - run: | - echo "Taking screenshot of web app..." - yarn playwright screenshot http://localhost:8081 /Users/runner/skia-test-screenshot-web.png || echo "Failed to capture screenshot" - - - name: Upload screenshot - if: always() - uses: actions/upload-artifact@v7 - with: - name: web-screenshot-${{ github.run_id }} - path: /Users/runner/skia-test-screenshot-web.png - if-no-files-found: ignore - - - name: Print test summary - if: always() - run: | - echo "================================================================" - echo "Web Test Summary:" - echo "================================================================" - echo "✓ Created Expo app with Skia template" - echo "✓ Installed @shopify/react-native-skia@${{ inputs.skia_version }}" - echo "✓ Started web server" - echo "✓ Web app accessible at http://localhost:8081" - echo "================================================================" diff --git a/.github/workflows/wcandillon-test-windows.yml b/.github/workflows/wcandillon-test-windows.yml deleted file mode 100644 index 583d7ce09f..0000000000 --- a/.github/workflows/wcandillon-test-windows.yml +++ /dev/null @@ -1,24 +0,0 @@ -# OWNER: wcandillon/react-native-skia -# Manual-dispatch Windows build check. Mirrors the build-windows-library job -# that used to live in CI. Runs on a GitHub-hosted windows-latest runner. -name: wcandillon - Test Windows -on: - workflow_dispatch: - -jobs: - build-windows-library: - if: ${{ github.repository == 'wcandillon/react-native-skia' }} - runs-on: windows-latest - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.0 - with: - submodules: recursive - - - name: Setup - uses: ./.github/actions/setup - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build package - run: yarn build From b26bff6bf7b40980cc8c6b5fff27e9a54ad2d6ec Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 29 Jul 2026 14:41:12 +0200 Subject: [PATCH 3/3] =?UTF-8?q?chore(=F0=9F=90=99):=20run=20graphite=20tes?= =?UTF-8?q?ts=20on=20iOS=20(#3981)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-graphite.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/ci-graphite.yml b/.github/workflows/ci-graphite.yml index b147aec1c7..9f0f1a2323 100644 --- a/.github/workflows/ci-graphite.yml +++ b/.github/workflows/ci-graphite.yml @@ -257,12 +257,4 @@ jobs: - name: Run e2e tests working-directory: packages/skia - # On Graphite we run the Paths render test plus the WebGPU specs. - # ArrayBuffer, ComputeShader, ErrorScope, ImageBitmapBounds and - # DawnToggles are pure surface.eval round-trips that assert on returned - # values. The external-texture specs (ExternalTexture, - # ImportExternalTexture, SharedTextureMemory) additionally exercise - # NativeBuffer import and GPU read-back; they self-validate via - # copyTextureToBuffer (not Skia image readPixels) and skip themselves - # where NativeBuffer/createImageBitmap are unavailable. - run: CI=true E2E=true yarn test -i "e2e/(Paths|ArrayBuffer|ComputeShader|ErrorScope|ImageBitmapBounds|DawnToggles|ExternalTexture|ImportExternalTexture|SharedTextureMemory)" + run: CI=true yarn e2e --testPathIgnorePatterns "Paragraph|Atlas"