@shopify/react-native-skia 2.6.4 → 2.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/android/CMakeLists.txt +7 -4
  2. package/android/build.gradle +22 -3
  3. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +62 -0
  4. package/apple/RNSkApplePlatformContext.h +2 -0
  5. package/apple/RNSkApplePlatformContext.mm +71 -0
  6. package/apple/RNWebGPUAppleNativeBuffer.mm +33 -0
  7. package/cpp/api/JsiNativeBuffer.h +9 -1
  8. package/cpp/api/JsiSkAnimatedImageFactory.h +1 -1
  9. package/cpp/api/JsiSkApi.h +2 -2
  10. package/cpp/api/JsiSkCanvas.h +1 -1
  11. package/cpp/api/JsiSkDataFactory.h +1 -1
  12. package/cpp/api/JsiSkFont.h +1 -1
  13. package/cpp/api/JsiSkFontMgr.h +1 -1
  14. package/cpp/api/JsiSkHostObjects.h +3 -3
  15. package/cpp/api/JsiSkImage.h +2 -2
  16. package/cpp/api/JsiSkImageFactory.h +2 -2
  17. package/cpp/api/JsiSkPath.h +1 -1
  18. package/cpp/api/JsiSkPathFactory.h +1 -1
  19. package/cpp/api/JsiSkSurface.h +13 -5
  20. package/cpp/api/JsiSkTypeface.h +1 -1
  21. package/cpp/api/JsiSkTypefaceFontProvider.h +1 -1
  22. package/cpp/api/JsiSkiaContext.h +2 -2
  23. package/cpp/api/JsiTextureInfo.h +1 -1
  24. package/cpp/api/JsiVideo.h +2 -2
  25. package/cpp/api/recorder/Drawings.h +1 -1
  26. package/cpp/api/recorder/JsiRecorder.h +4 -4
  27. package/cpp/api/recorder/RNRecorder.h +1 -1
  28. package/cpp/jsi/ViewProperty.h +1 -1
  29. package/cpp/rnskia/RNDawnContext.h +13 -0
  30. package/cpp/rnskia/RNDawnUtils.h +11 -1
  31. package/cpp/rnskia/RNSkJsiViewApi.h +2 -2
  32. package/cpp/rnskia/RNSkManager.cpp +88 -2
  33. package/cpp/rnskia/RNSkPictureView.h +4 -4
  34. package/cpp/rnskia/RNSkPlatformContext.h +7 -0
  35. package/cpp/rnskia/RNSkView.h +9 -6
  36. package/cpp/rnwgpu/ArrayBuffer.h +51 -7
  37. package/cpp/rnwgpu/api/AppleNativeBuffer.h +22 -0
  38. package/cpp/rnwgpu/api/Convertors.h +33 -11
  39. package/cpp/rnwgpu/api/GPUAdapter.cpp +28 -2
  40. package/cpp/rnwgpu/api/GPUBuffer.h +1 -1
  41. package/cpp/rnwgpu/api/GPUDevice.cpp +29 -2
  42. package/cpp/rnwgpu/api/GPUDevice.h +6 -0
  43. package/cpp/rnwgpu/api/GPUExternalTexture.cpp +139 -0
  44. package/cpp/rnwgpu/api/GPUExternalTexture.h +52 -2
  45. package/cpp/rnwgpu/api/GPUQueue.cpp +50 -45
  46. package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +82 -0
  47. package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +70 -0
  48. package/cpp/rnwgpu/api/ImageBitmap.h +62 -0
  49. package/cpp/rnwgpu/api/NativeBufferUtils.h +87 -0
  50. package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +4 -1
  51. package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +1 -1
  52. package/cpp/rnwgpu/api/descriptors/GPUDawnTogglesDescriptor.h +56 -0
  53. package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +10 -0
  54. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +43 -24
  55. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +9 -9
  56. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +1 -1
  57. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +2 -2
  58. package/cpp/rnwgpu/api/descriptors/GPUSharedTextureMemoryDescriptor.h +73 -0
  59. package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +1 -1
  60. package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +1 -1
  61. package/cpp/skia/include/core/SkRegion.h +10 -5
  62. package/cpp/skia/include/effects/SkRuntimeEffect.h +2 -2
  63. package/cpp/skia/include/gpu/graphite/Context.h +1 -1
  64. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  65. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  66. package/lib/commonjs/skia/types/WebGPU.d.ts +88 -0
  67. package/lib/commonjs/skia/types/WebGPU.js +6 -0
  68. package/lib/commonjs/skia/types/WebGPU.js.map +1 -0
  69. package/lib/commonjs/skia/types/index.d.ts +1 -0
  70. package/lib/commonjs/skia/types/index.js +11 -0
  71. package/lib/commonjs/skia/types/index.js.map +1 -1
  72. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  73. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +19 -0
  74. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  75. package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
  76. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  77. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  78. package/lib/module/skia/types/WebGPU.d.ts +88 -0
  79. package/lib/module/skia/types/WebGPU.js +2 -0
  80. package/lib/module/skia/types/WebGPU.js.map +1 -0
  81. package/lib/module/skia/types/index.d.ts +1 -0
  82. package/lib/module/skia/types/index.js +1 -0
  83. package/lib/module/skia/types/index.js.map +1 -1
  84. package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  85. package/lib/module/skia/web/JsiSkNativeBufferFactory.js +19 -0
  86. package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  87. package/lib/module/skia/web/JsiSkPath.js.map +1 -1
  88. package/lib/module/web/LoadSkiaWeb.js +1 -2
  89. package/lib/module/web/LoadSkiaWeb.js.map +1 -1
  90. package/lib/typescript/lib/commonjs/skia/types/WebGPU.d.ts +1 -0
  91. package/lib/typescript/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  92. package/lib/typescript/lib/module/skia/types/WebGPU.d.ts +1 -0
  93. package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
  94. package/lib/typescript/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  95. package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +10 -1
  96. package/lib/typescript/src/skia/types/WebGPU.d.ts +88 -0
  97. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  98. package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +1 -0
  99. package/package.json +10 -8
  100. package/react-native-skia.podspec +59 -7
  101. package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +10 -1
  102. package/src/skia/types/WebGPU.ts +108 -0
  103. package/src/skia/types/index.ts +1 -0
  104. package/src/skia/web/JsiSkNativeBufferFactory.ts +20 -0
  105. package/src/skia/web/JsiSkPath.ts +8 -2
  106. package/scripts/install-libs.js +0 -133
@@ -1 +1 @@
1
- {"version":3,"names":["CanvasKitInit","ckSharedPromise","LoadSkiaWeb","opts","_ckSharedPromise","global","CanvasKit","undefined","LoadSkia"],"sources":["LoadSkiaWeb.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport CanvasKitInit from \"canvaskit-wasm/bin/full/canvaskit\";\nimport type {\n CanvasKit as CanvasKitType,\n CanvasKitInitOptions,\n} from \"canvaskit-wasm\";\n\ndeclare global {\n var CanvasKit: CanvasKitType;\n}\n\nlet ckSharedPromise: Promise<CanvasKitType>;\n\nexport const LoadSkiaWeb = async (opts?: CanvasKitInitOptions) => {\n if (global.CanvasKit !== undefined) {\n return;\n }\n ckSharedPromise = ckSharedPromise ?? CanvasKitInit(opts);\n const CanvasKit = await ckSharedPromise;\n // The CanvasKit API is stored on the global object and used\n // to create the JsiSKApi in the Skia.web.ts file.\n global.CanvasKit = CanvasKit;\n};\n\n// We keep this function for backward compatibility\nexport const LoadSkia = LoadSkiaWeb;\n"],"mappings":"AAAA;AACA;AACA,OAAOA,aAAa,MAAM,mCAAmC;AAU7D,IAAIC,eAAuC;AAE3C,OAAO,MAAMC,WAAW,GAAG,MAAOC,IAA2B,IAAK;EAAA,IAAAC,gBAAA;EAChE,IAAIC,MAAM,CAACC,SAAS,KAAKC,SAAS,EAAE;IAClC;EACF;EACAN,eAAe,IAAAG,gBAAA,GAAGH,eAAe,cAAAG,gBAAA,cAAAA,gBAAA,GAAIJ,aAAa,CAACG,IAAI,CAAC;EACxD,MAAMG,SAAS,GAAG,MAAML,eAAe;EACvC;EACA;EACAI,MAAM,CAACC,SAAS,GAAGA,SAAS;AAC9B,CAAC;;AAED;AACA,OAAO,MAAME,QAAQ,GAAGN,WAAW","ignoreList":[]}
1
+ {"version":3,"names":["CanvasKitInit","ckSharedPromise","LoadSkiaWeb","opts","global","CanvasKit","undefined","LoadSkia"],"sources":["LoadSkiaWeb.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport CanvasKitInit from \"canvaskit-wasm/bin/full/canvaskit\";\nimport type {\n CanvasKit as CanvasKitType,\n CanvasKitInitOptions,\n} from \"canvaskit-wasm\";\n\ndeclare global {\n var CanvasKit: CanvasKitType;\n}\n\nlet ckSharedPromise: Promise<CanvasKitType>;\n\nexport const LoadSkiaWeb = async (opts?: CanvasKitInitOptions) => {\n if (global.CanvasKit !== undefined) {\n return;\n }\n ckSharedPromise = ckSharedPromise ?? CanvasKitInit(opts);\n const CanvasKit = await ckSharedPromise;\n // The CanvasKit API is stored on the global object and used\n // to create the JsiSKApi in the Skia.web.ts file.\n global.CanvasKit = CanvasKit;\n};\n\n// We keep this function for backward compatibility\nexport const LoadSkia = LoadSkiaWeb;\n"],"mappings":"AAAA;AACA;AACA,OAAOA,aAAa,MAAM,mCAAmC;AAU7D,IAAIC,eAAuC;AAE3C,OAAO,MAAMC,WAAW,GAAG,MAAOC,IAA2B,IAAK;EAChE,IAAIC,MAAM,CAACC,SAAS,KAAKC,SAAS,EAAE;IAClC;EACF;EACAL,eAAe,GAAGA,eAAe,aAAfA,eAAe,cAAfA,eAAe,GAAID,aAAa,CAACG,IAAI,CAAC;EACxD,MAAME,SAAS,GAAG,MAAMJ,eAAe;EACvC;EACA;EACAG,MAAM,CAACC,SAAS,GAAGA,SAAS;AAC9B,CAAC;;AAED;AACA,OAAO,MAAME,QAAQ,GAAGL,WAAW","ignoreList":[]}
@@ -0,0 +1 @@
1
+ export const __esModule: boolean;
@@ -1,6 +1,7 @@
1
1
  export const __esModule: boolean;
2
2
  export class JsiSkNativeBufferFactory extends _Host.Host {
3
3
  MakeFromImage(image: any): OffscreenCanvas;
4
+ MakeTestBuffer(width: any, height: any): OffscreenCanvas;
4
5
  Release(_nativeBuffer: any): void;
5
6
  }
6
7
  import _Host = require("./Host");
@@ -0,0 +1 @@
1
+ export {};
@@ -27,6 +27,7 @@ export * from "./TextBlob";
27
27
  export * from "./Paragraph";
28
28
  export * from "./Matrix4";
29
29
  export * from "./NativeBuffer";
30
+ export * from "./WebGPU";
30
31
  export * from "./Recorder";
31
32
  export * from "./Video";
32
33
  export * from "./Skottie";
@@ -1,5 +1,6 @@
1
1
  export class JsiSkNativeBufferFactory extends Host {
2
2
  MakeFromImage(image: any): OffscreenCanvas;
3
+ MakeTestBuffer(width: any, height: any): OffscreenCanvas;
3
4
  Release(_nativeBuffer: any): void;
4
5
  }
5
6
  import { Host } from "./Host";
@@ -14,7 +14,16 @@ export interface NativeBufferFactory {
14
14
  */
15
15
  MakeFromImage: (image: SkImage) => NativeBuffer;
16
16
  /**
17
- * Release a native buffer that was created with `MakeFromImage`.
17
+ * Create a native buffer of the given size filled with a procedural test
18
+ * pattern (RGB gradient + diagonal stripes), entirely on the CPU. Useful for
19
+ * examples and tests that need a buffer to feed into
20
+ * `GPUDevice.importExternalTexture` without a camera/video source. Release it
21
+ * with `Release`.
22
+ */
23
+ MakeTestBuffer: (width: number, height: number) => NativeBuffer;
24
+ /**
25
+ * Release a native buffer that was created with `MakeFromImage` or
26
+ * `MakeTestBuffer`.
18
27
  */
19
28
  Release: (nativeBuffer: NativeBuffer) => void;
20
29
  }
@@ -0,0 +1,88 @@
1
+ import type { NativeBuffer } from "./NativeBuffer";
2
+ /**
3
+ * Descriptor for {@link GPUDevice.importExternalTexture} when the source is a
4
+ * Skia NativeBuffer (Skia has no WebCodecs `VideoFrame`).
5
+ *
6
+ * `source` is the handle returned by `Skia.NativeBuffer.MakeFromImage`: a
7
+ * `CVPixelBufferRef` on Apple, an `AHardwareBuffer*` on Android. The caller
8
+ * owns its lifetime (release it with `Skia.NativeBuffer.Release`) and must keep
9
+ * it alive until the imported texture is destroyed.
10
+ */
11
+ export interface SkiaGPUExternalTextureDescriptor extends GPUObjectDescriptorBase {
12
+ source: NativeBuffer;
13
+ /** Rotation applied while sampling, in degrees. One of 0 | 90 | 180 | 270. */
14
+ rotation?: number;
15
+ /** Mirror horizontally while sampling. */
16
+ mirrored?: boolean;
17
+ }
18
+ /**
19
+ * Descriptor for {@link GPUDevice.importSharedTextureMemory}. `handle` is the
20
+ * NativeBuffer returned by `Skia.NativeBuffer.MakeFromImage` (see
21
+ * {@link SkiaGPUExternalTextureDescriptor} for the platform-specific types and
22
+ * lifetime rules).
23
+ */
24
+ export interface GPUSharedTextureMemoryDescriptor extends GPUObjectDescriptorBase {
25
+ handle: NativeBuffer;
26
+ }
27
+ /**
28
+ * Shared texture memory imported from a platform native buffer via
29
+ * {@link GPUDevice.importSharedTextureMemory}. Create a texture that aliases
30
+ * the memory, then bracket the GPU work that touches it with
31
+ * {@link GPUSharedTextureMemory.beginAccess} / {@link GPUSharedTextureMemory.endAccess}.
32
+ */
33
+ export interface GPUSharedTextureMemory extends GPUObjectBase {
34
+ /** Create a texture that aliases the shared memory. */
35
+ createTexture(descriptor?: GPUTextureDescriptor): GPUTexture;
36
+ /**
37
+ * Acquire the memory for GPU access. `initialized` marks whether the existing
38
+ * contents should be preserved (pass `true` for an already-rendered frame).
39
+ * Returns `false` if access could not be acquired.
40
+ */
41
+ beginAccess(texture: GPUTexture, initialized: boolean): boolean;
42
+ /**
43
+ * Release the memory after the GPU work that accessed it has been submitted.
44
+ * Returns `false` on failure.
45
+ */
46
+ endAccess(texture: GPUTexture): boolean;
47
+ }
48
+ /**
49
+ * Dawn-specific toggles, passed via {@link GPUDeviceDescriptor.dawnToggles} to
50
+ * `adapter.requestDevice`. This is a non-spec, Dawn-only extension; see Dawn's
51
+ * toggle list for valid names.
52
+ */
53
+ export interface GPUDawnTogglesDescriptor {
54
+ enabledToggles?: string[];
55
+ disabledToggles?: string[];
56
+ }
57
+ declare global {
58
+ interface GPUDeviceDescriptor {
59
+ /** Dawn-specific toggles (Skia/Graphite extension, non-spec). */
60
+ dawnToggles?: GPUDawnTogglesDescriptor;
61
+ }
62
+ interface GPUExternalTexture {
63
+ /**
64
+ * Skia extension: end the imported buffer's shared-memory access window and
65
+ * release the underlying resources. Call right after the `queue.submit()`
66
+ * that sampled this texture (never before). Idempotent, and also runs at
67
+ * garbage collection as a fallback.
68
+ */
69
+ destroy(): void;
70
+ }
71
+ interface GPUDevice {
72
+ /**
73
+ * Skia extension: import a NativeBuffer (from
74
+ * `Skia.NativeBuffer.MakeFromImage`) as a {@link GPUExternalTexture}, sampled
75
+ * with `texture_external` in WGSL. The returned texture owns the
76
+ * shared-memory access window; call `destroy()` on it after the sampling
77
+ * `queue.submit()`.
78
+ */
79
+ importExternalTexture(descriptor: SkiaGPUExternalTextureDescriptor): GPUExternalTexture;
80
+ /**
81
+ * Skia extension: import a NativeBuffer (from
82
+ * `Skia.NativeBuffer.MakeFromImage`) as {@link GPUSharedTextureMemory}, the
83
+ * lower-level path that lets you create an aliasing texture and manage the
84
+ * begin/end access window yourself.
85
+ */
86
+ importSharedTextureMemory(descriptor: GPUSharedTextureMemoryDescriptor): GPUSharedTextureMemory;
87
+ }
88
+ }
@@ -30,6 +30,7 @@ export * from "./Size";
30
30
  export * from "./Paragraph";
31
31
  export * from "./Matrix4";
32
32
  export * from "./NativeBuffer";
33
+ export * from "./WebGPU";
33
34
  export * from "./Recorder";
34
35
  export * from "./Video";
35
36
  export * from "./Skottie";
@@ -4,5 +4,6 @@ import { Host } from "./Host";
4
4
  export declare class JsiSkNativeBufferFactory extends Host implements NativeBufferFactory {
5
5
  constructor(CanvasKit: CanvasKit);
6
6
  MakeFromImage(image: SkImage): NativeBuffer;
7
+ MakeTestBuffer(width: number, height: number): NativeBuffer;
7
8
  Release(_nativeBuffer: NativeBuffer): void;
8
9
  }
package/package.json CHANGED
@@ -5,11 +5,10 @@
5
5
  "provenance": true
6
6
  },
7
7
  "bin": {
8
- "install-skia": "scripts/install-libs.js",
9
8
  "setup-skia-web": "scripts/setup-canvaskit.js"
10
9
  },
11
10
  "title": "React Native Skia",
12
- "version": "2.6.4",
11
+ "version": "2.6.5",
13
12
  "description": "High-performance React Native Graphics using Skia",
14
13
  "main": "lib/module/index.js",
15
14
  "react-native": "src/index.ts",
@@ -17,7 +16,6 @@
17
16
  "types": "lib/typescript/index.d.ts",
18
17
  "files": [
19
18
  "scripts/setup-canvaskit.js",
20
- "scripts/install-libs.js",
21
19
  "src/**",
22
20
  "lib/**",
23
21
  "!**/__tests__/**",
@@ -37,7 +35,6 @@
37
35
  "dist/**"
38
36
  ],
39
37
  "scripts": {
40
- "postinstall": "node scripts/install-libs.js",
41
38
  "lint": "eslint . --ext .ts,.tsx --max-warnings 0 --cache --fix",
42
39
  "tsc": "tsc --noEmit",
43
40
  "test": "jest",
@@ -47,8 +44,8 @@
47
44
  "clean-skia": "yarn rimraf ./libs && yarn rimraf ../../externals/skia/out",
48
45
  "build-skia": "tsx ./scripts/build-skia.ts",
49
46
  "copy-skia-headers": "tsx ./scripts/copy-skia-headers.ts",
47
+ "install-skia": "tsx ./scripts/install-skia.ts",
50
48
  "install-skia-graphite": "tsx ./scripts/install-skia-graphite.ts",
51
- "install-skia": "node scripts/install-libs.js",
52
49
  "clang-format": "yarn clang-format-ios && yarn clang-format-android && yarn clang-format-common",
53
50
  "clang-format-ios": "find apple/ -iname '*.h' -o -iname '*.mm' -o -iname '*.cpp' | xargs clang-format -i",
54
51
  "clang-format-android": "find android/cpp/ -iname '*.h' -o -iname '*.m' -o -iname '*.cpp' | xargs clang-format -i",
@@ -92,8 +89,13 @@
92
89
  }
93
90
  },
94
91
  "devDependencies": {
95
- "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
92
+ "@babel/plugin-transform-class-properties": "^7.28.0",
96
93
  "@babel/plugin-transform-explicit-resource-management": "^7.28.0",
94
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.0",
95
+ "@babel/preset-env": "^7.28.0",
96
+ "@babel/preset-flow": "^7.28.0",
97
+ "@babel/preset-react": "^7.28.0",
98
+ "@babel/preset-typescript": "^7.28.0",
97
99
  "@blazediff/core": "^1.4.0",
98
100
  "@semantic-release/commit-analyzer": "^13.0.0",
99
101
  "@semantic-release/exec": "^7.0.3",
@@ -121,11 +123,11 @@
121
123
  "rimraf": "3.0.2",
122
124
  "semantic-release": "^24.1.0",
123
125
  "semantic-release-yarn": "^3.0.2",
124
- "tar": "^7.5.11",
126
+ "tar": "^7.5.16",
125
127
  "ts-jest": "29.4.3",
126
128
  "tsx": "^4.21.0",
127
129
  "typescript": "^5.2.2",
128
- "ws": "8.20.1"
130
+ "ws": "8.21.0"
129
131
  },
130
132
  "dependencies": {
131
133
  "canvaskit-wasm": "0.41.0",
@@ -1,6 +1,7 @@
1
1
  # @shopify/react-native-skia.podspec
2
2
 
3
3
  require "json"
4
+ require "fileutils"
4
5
 
5
6
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
6
7
 
@@ -8,6 +9,55 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
8
9
  use_graphite = File.exist?(File.join(__dir__, 'libs', '.graphite'))
9
10
  puts "-- SK_GRAPHITE: #{use_graphite ? 'ON' : 'OFF'} (detected via libs/.graphite marker file)"
10
11
 
12
+ # Resolve a node package directory using Node's own module resolution
13
+ # (mirrors `require.resolve(pkg/package.json)`). Returns nil if it can't be found.
14
+ # Defined as a lambda (not a `def`) because CocoaPods evaluates the podspec inside
15
+ # the `Pod` module, where top-level methods are not reachable at the call site.
16
+ resolve_node_package = lambda do |name, base_dir|
17
+ script = "process.stdout.write(require('path').dirname(require.resolve('#{name}/package.json')))"
18
+ dir = Dir.chdir(base_dir) { `node -e "#{script}" 2>/dev/null`.strip }
19
+ dir.empty? ? nil : dir
20
+ end
21
+
22
+ # Copy the prebuilt xcframeworks from the Skia npm packages into libs/<platform>.
23
+ #
24
+ # This replaces what the old npm `postinstall` script used to do. We do it here, at
25
+ # `pod install` time, so we no longer rely on a lifecycle script. CocoaPods always
26
+ # re-evaluates the podspec for path-based pods, so this runs on every install; to keep
27
+ # it cache-friendly we stamp the copied package version into libs/<platform>/.version
28
+ # and skip the copy when it already matches. On a version bump the frameworks are
29
+ # re-copied and CocoaPods picks up the change. This is best-effort: if `pod install`
30
+ # does not detect the change, a clean reinstall fixes it (acceptable until the upcoming
31
+ # Swift Package Manager migration).
32
+ install_apple_skia_libs = lambda do |base_dir|
33
+ { 'ios' => 'react-native-skia-apple-ios',
34
+ 'macos' => 'react-native-skia-apple-macos',
35
+ 'tvos' => 'react-native-skia-apple-tvos' }.each do |platform, pkg_name|
36
+ pkg_dir = resolve_node_package.call(pkg_name, base_dir)
37
+ next if pkg_dir.nil?
38
+
39
+ src = File.join(pkg_dir, 'libs')
40
+ next unless Dir.exist?(src) && !Dir.glob(File.join(src, '*.xcframework')).empty?
41
+
42
+ version = JSON.parse(File.read(File.join(pkg_dir, 'package.json')))['version'].to_s
43
+ dest = File.join(base_dir, 'libs', platform)
44
+ marker = File.join(dest, '.version')
45
+
46
+ # Already up to date: leave the files untouched so CocoaPods keeps its cache.
47
+ next if File.exist?(marker) && File.read(marker).strip == version
48
+
49
+ Pod::UI.puts "react-native-skia: installing #{platform} Skia frameworks (#{version})"
50
+ FileUtils.rm_rf(dest)
51
+ FileUtils.mkdir_p(dest)
52
+ Dir.glob(File.join(src, '*.xcframework')).each { |xcf| FileUtils.cp_r(xcf, dest) }
53
+ File.write(marker, version)
54
+ end
55
+ end
56
+
57
+ # Graphite downloads its binaries directly into libs/; only the default build needs
58
+ # the npm packages copied in.
59
+ install_apple_skia_libs.call(__dir__) unless use_graphite
60
+
11
61
  # Set preprocessor definitions based on GRAPHITE flag
12
62
  preprocessor_defs = use_graphite ?
13
63
  '$(inherited) SK_GRAPHITE=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1' :
@@ -21,22 +71,24 @@ framework_names = ['libskia', 'libsvg', 'libskshaper', 'libskparagraph',
21
71
  # Add Dawn library for Graphite builds (contains dawn::native symbols)
22
72
  framework_names += ['libdawn_combined'] if use_graphite
23
73
 
24
- # Verify that prebuilt binaries have been installed by the postinstall script
74
+ # Verify that the prebuilt binaries are available (copied in above, or downloaded by
75
+ # install-skia-graphite for Graphite builds).
25
76
  unless Dir.exist?(File.join(__dir__, 'libs', 'ios')) && Dir.exist?(File.join(__dir__, 'libs', 'macos'))
26
77
  Pod::UI.warn "#{'-' * 72}"
27
78
  Pod::UI.warn "react-native-skia: Skia prebuilt binaries not found in libs/!"
28
79
  Pod::UI.warn ""
29
- Pod::UI.warn "Run the following command to install them:"
30
- Pod::UI.warn " npx install-skia"
80
+ Pod::UI.warn "Make sure dependencies are installed (yarn install / npm install) so that"
81
+ Pod::UI.warn "the react-native-skia-apple-* packages are present, then run `pod install` again."
31
82
  Pod::UI.warn "#{'-' * 72}"
32
- raise "react-native-skia: Skia prebuilt binaries not found. Run `npx install-skia` to fix this."
83
+ raise "react-native-skia: Skia prebuilt binaries not found. Run `yarn install` then `pod install` to fix this."
33
84
  end
34
85
 
35
86
  # Build platform-specific framework paths (relative to pod's libs directory)
36
- # xcframeworks are copied into libs/ by the npm postinstall script (scripts/install-libs.js)
87
+ # xcframeworks are copied into libs/ by install_apple_skia_libs above (default build)
88
+ # or downloaded by install-skia-graphite (Graphite build).
37
89
  ios_frameworks = framework_names.map { |f| "libs/ios/#{f}.xcframework" }
38
90
  osx_frameworks = framework_names.map { |f| "libs/macos/#{f}.xcframework" }
39
- # tvOS frameworks - check if libs/tvos/ exists (populated by postinstall before pod install runs)
91
+ # tvOS frameworks - check if libs/tvos/ exists (only populated for the default build)
40
92
  tvos_frameworks = if use_graphite || !Dir.exist?(File.join(__dir__, 'libs', 'tvos'))
41
93
  []
42
94
  else
@@ -65,7 +117,7 @@ Pod::Spec.new do |s|
65
117
  'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_defs,
66
118
  'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
67
119
  'DEFINES_MODULE' => 'YES',
68
- "HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/cpp/"/** "$(PODS_TARGET_SRCROOT)/cpp" "$(PODS_TARGET_SRCROOT)/cpp/skia" "$(PODS_TARGET_SRCROOT)/cpp/jsi2" "$(PODS_TARGET_SRCROOT)/cpp/rnwgpu" "$(PODS_TARGET_SRCROOT)/cpp/rnwgpu/api" "$(PODS_TARGET_SRCROOT)/cpp/rnwgpu/api/descriptors" "$(PODS_TARGET_SRCROOT)/cpp/rnwgpu/async" "$(PODS_TARGET_SRCROOT)/cpp/dawn/include"'
120
+ "HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/cpp"/** "$(PODS_TARGET_SRCROOT)/cpp" "$(PODS_TARGET_SRCROOT)/cpp/skia" "$(PODS_TARGET_SRCROOT)/cpp/dawn/include"'
69
121
  }
70
122
 
71
123
  s.frameworks = ['MetalKit', 'AVFoundation', 'AVKit', 'CoreMedia']
@@ -40,7 +40,16 @@ export interface NativeBufferFactory {
40
40
  */
41
41
  MakeFromImage: (image: SkImage) => NativeBuffer;
42
42
  /**
43
- * Release a native buffer that was created with `MakeFromImage`.
43
+ * Create a native buffer of the given size filled with a procedural test
44
+ * pattern (RGB gradient + diagonal stripes), entirely on the CPU. Useful for
45
+ * examples and tests that need a buffer to feed into
46
+ * `GPUDevice.importExternalTexture` without a camera/video source. Release it
47
+ * with `Release`.
48
+ */
49
+ MakeTestBuffer: (width: number, height: number) => NativeBuffer;
50
+ /**
51
+ * Release a native buffer that was created with `MakeFromImage` or
52
+ * `MakeTestBuffer`.
44
53
  */
45
54
  Release: (nativeBuffer: NativeBuffer) => void;
46
55
  }
@@ -0,0 +1,108 @@
1
+ import type { NativeBuffer } from "./NativeBuffer";
2
+
3
+ // Skia's Graphite/Dawn backend extends the standard WebGPU API (typed by
4
+ // @webgpu/types) with a few Skia- and Dawn-specific entry points. These are
5
+ // only available on native (SK_GRAPHITE) builds, reachable through
6
+ // `Skia.getDevice()`.
7
+ //
8
+ // The exported interfaces below describe the descriptors and objects those
9
+ // entry points use; the `declare global` block augments the standard WebGPU
10
+ // interfaces so the new methods are typed without casting to `any`.
11
+
12
+ /**
13
+ * Descriptor for {@link GPUDevice.importExternalTexture} when the source is a
14
+ * Skia NativeBuffer (Skia has no WebCodecs `VideoFrame`).
15
+ *
16
+ * `source` is the handle returned by `Skia.NativeBuffer.MakeFromImage`: a
17
+ * `CVPixelBufferRef` on Apple, an `AHardwareBuffer*` on Android. The caller
18
+ * owns its lifetime (release it with `Skia.NativeBuffer.Release`) and must keep
19
+ * it alive until the imported texture is destroyed.
20
+ */
21
+ export interface SkiaGPUExternalTextureDescriptor extends GPUObjectDescriptorBase {
22
+ source: NativeBuffer;
23
+ /** Rotation applied while sampling, in degrees. One of 0 | 90 | 180 | 270. */
24
+ rotation?: number;
25
+ /** Mirror horizontally while sampling. */
26
+ mirrored?: boolean;
27
+ }
28
+
29
+ /**
30
+ * Descriptor for {@link GPUDevice.importSharedTextureMemory}. `handle` is the
31
+ * NativeBuffer returned by `Skia.NativeBuffer.MakeFromImage` (see
32
+ * {@link SkiaGPUExternalTextureDescriptor} for the platform-specific types and
33
+ * lifetime rules).
34
+ */
35
+ export interface GPUSharedTextureMemoryDescriptor extends GPUObjectDescriptorBase {
36
+ handle: NativeBuffer;
37
+ }
38
+
39
+ /**
40
+ * Shared texture memory imported from a platform native buffer via
41
+ * {@link GPUDevice.importSharedTextureMemory}. Create a texture that aliases
42
+ * the memory, then bracket the GPU work that touches it with
43
+ * {@link GPUSharedTextureMemory.beginAccess} / {@link GPUSharedTextureMemory.endAccess}.
44
+ */
45
+ export interface GPUSharedTextureMemory extends GPUObjectBase {
46
+ /** Create a texture that aliases the shared memory. */
47
+ createTexture(descriptor?: GPUTextureDescriptor): GPUTexture;
48
+ /**
49
+ * Acquire the memory for GPU access. `initialized` marks whether the existing
50
+ * contents should be preserved (pass `true` for an already-rendered frame).
51
+ * Returns `false` if access could not be acquired.
52
+ */
53
+ beginAccess(texture: GPUTexture, initialized: boolean): boolean;
54
+ /**
55
+ * Release the memory after the GPU work that accessed it has been submitted.
56
+ * Returns `false` on failure.
57
+ */
58
+ endAccess(texture: GPUTexture): boolean;
59
+ }
60
+
61
+ /**
62
+ * Dawn-specific toggles, passed via {@link GPUDeviceDescriptor.dawnToggles} to
63
+ * `adapter.requestDevice`. This is a non-spec, Dawn-only extension; see Dawn's
64
+ * toggle list for valid names.
65
+ */
66
+ export interface GPUDawnTogglesDescriptor {
67
+ enabledToggles?: string[];
68
+ disabledToggles?: string[];
69
+ }
70
+
71
+ declare global {
72
+ interface GPUDeviceDescriptor {
73
+ /** Dawn-specific toggles (Skia/Graphite extension, non-spec). */
74
+ dawnToggles?: GPUDawnTogglesDescriptor;
75
+ }
76
+
77
+ interface GPUExternalTexture {
78
+ /**
79
+ * Skia extension: end the imported buffer's shared-memory access window and
80
+ * release the underlying resources. Call right after the `queue.submit()`
81
+ * that sampled this texture (never before). Idempotent, and also runs at
82
+ * garbage collection as a fallback.
83
+ */
84
+ destroy(): void;
85
+ }
86
+
87
+ interface GPUDevice {
88
+ /**
89
+ * Skia extension: import a NativeBuffer (from
90
+ * `Skia.NativeBuffer.MakeFromImage`) as a {@link GPUExternalTexture}, sampled
91
+ * with `texture_external` in WGSL. The returned texture owns the
92
+ * shared-memory access window; call `destroy()` on it after the sampling
93
+ * `queue.submit()`.
94
+ */
95
+ importExternalTexture(
96
+ descriptor: SkiaGPUExternalTextureDescriptor
97
+ ): GPUExternalTexture;
98
+ /**
99
+ * Skia extension: import a NativeBuffer (from
100
+ * `Skia.NativeBuffer.MakeFromImage`) as {@link GPUSharedTextureMemory}, the
101
+ * lower-level path that lets you create an aliasing texture and manage the
102
+ * begin/end access window yourself.
103
+ */
104
+ importSharedTextureMemory(
105
+ descriptor: GPUSharedTextureMemoryDescriptor
106
+ ): GPUSharedTextureMemory;
107
+ }
108
+ }
@@ -30,6 +30,7 @@ export * from "./Size";
30
30
  export * from "./Paragraph";
31
31
  export * from "./Matrix4";
32
32
  export * from "./NativeBuffer";
33
+ export * from "./WebGPU";
33
34
  export * from "./Recorder";
34
35
  export * from "./Video";
35
36
  export * from "./Skottie";
@@ -25,6 +25,26 @@ export class JsiSkNativeBufferFactory
25
25
  return canvas;
26
26
  }
27
27
 
28
+ MakeTestBuffer(width: number, height: number): NativeBuffer {
29
+ const pixels = new Uint8ClampedArray(width * height * 4);
30
+ for (let y = 0; y < height; y++) {
31
+ for (let x = 0; x < width; x++) {
32
+ const i = (y * width + x) * 4;
33
+ pixels[i + 0] = Math.floor((x * 255) / Math.max(width - 1, 1));
34
+ pixels[i + 1] = Math.floor((y * 255) / Math.max(height - 1, 1));
35
+ pixels[i + 2] = (x + y) & 0x20 ? 220 : 30;
36
+ pixels[i + 3] = 0xff;
37
+ }
38
+ }
39
+ const canvas = new OffscreenCanvas(width, height);
40
+ const ctx = canvas.getContext("2d");
41
+ if (!ctx) {
42
+ throw new Error("Failed to get 2d context from canvas");
43
+ }
44
+ ctx.putImageData(new ImageData(pixels, width, height), 0, 0);
45
+ return canvas;
46
+ }
47
+
28
48
  Release(_nativeBuffer: NativeBuffer) {
29
49
  // it's a noop on Web
30
50
  }
@@ -447,7 +447,10 @@ export class JsiSkPath
447
447
  }
448
448
 
449
449
  simplify() {
450
- warnDeprecatedPathMethod("simplify", "Use Skia.Path.Simplify(path) instead.");
450
+ warnDeprecatedPathMethod(
451
+ "simplify",
452
+ "Use Skia.Path.Simplify(path) instead."
453
+ );
451
454
  const path = this.asPath();
452
455
  const result = path.makeSimplified();
453
456
  path.delete();
@@ -500,7 +503,10 @@ export class JsiSkPath
500
503
  }
501
504
 
502
505
  stroke(opts?: StrokeOpts) {
503
- warnDeprecatedPathMethod("stroke", "Use Skia.Path.Stroke(path, opts) instead.");
506
+ warnDeprecatedPathMethod(
507
+ "stroke",
508
+ "Use Skia.Path.Stroke(path, opts) instead."
509
+ );
504
510
  const path = this.asPath();
505
511
  const result = path.makeStroked(
506
512
  opts === undefined
@@ -1,133 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
-
4
- const path = require("path");
5
- const fs = require("fs");
6
-
7
- const useGraphite =
8
- process.env.SK_GRAPHITE === "1" ||
9
- (process.env.SK_GRAPHITE || "").toLowerCase() === "true";
10
- const prefix = useGraphite ? "react-native-skia-graphite" : "react-native-skia";
11
- const libsDir = path.join(__dirname, "..", "libs");
12
-
13
- function copySync(src, dest, options) {
14
- if (!src.includes("*")) {
15
- return fs.cpSync(src, dest, options);
16
- }
17
-
18
- const wildcardSplit = src.split("*");
19
- const basePath = wildcardSplit[0];
20
- const files = fs.readdirSync(basePath);
21
- files
22
- .filter((file) => file.endsWith(wildcardSplit[1]))
23
- .forEach((file) => {
24
- return fs.cpSync(
25
- path.join(basePath, file),
26
- path.join(dest, file),
27
- options
28
- );
29
- });
30
- }
31
-
32
- // --- Apple platforms ---
33
-
34
- let iosPackage, macosPackage;
35
- try {
36
- iosPackage = path.dirname(
37
- require.resolve(prefix + "-apple-ios/package.json")
38
- );
39
- macosPackage = path.dirname(
40
- require.resolve(prefix + "-apple-macos/package.json")
41
- );
42
- } catch (e) {
43
- console.error(
44
- "ERROR: Could not find " +
45
- prefix +
46
- "-apple-ios or " +
47
- prefix +
48
- "-apple-macos"
49
- );
50
- console.error("Make sure you have run yarn install or npm install");
51
- process.exit(1);
52
- }
53
-
54
- // Verify xcframeworks exist in the iOS package
55
- const iosXcf = path.join(iosPackage, "libs");
56
- if (
57
- !fs.existsSync(iosXcf) ||
58
- !fs.readdirSync(iosXcf).some((f) => f.endsWith(".xcframework"))
59
- ) {
60
- console.error(
61
- "ERROR: Skia prebuilt binaries not found in " + prefix + "-apple-ios!"
62
- );
63
- process.exit(1);
64
- }
65
-
66
- console.log("-- Skia iOS package: " + iosPackage);
67
- console.log("-- Skia macOS package: " + macosPackage);
68
-
69
- // Clean and copy Apple frameworks
70
- fs.rmSync(path.join(libsDir, "ios"), { recursive: true, force: true });
71
- fs.rmSync(path.join(libsDir, "macos"), { recursive: true, force: true });
72
- fs.rmSync(path.join(libsDir, "tvos"), { recursive: true, force: true });
73
- fs.mkdirSync(path.join(libsDir, "ios"), { recursive: true });
74
- fs.mkdirSync(path.join(libsDir, "macos"), { recursive: true });
75
-
76
- copySync(iosPackage + "/libs/*.xcframework", path.join(libsDir, "ios"), {
77
- recursive: true,
78
- });
79
- copySync(macosPackage + "/libs/*.xcframework", path.join(libsDir, "macos"), {
80
- recursive: true,
81
- });
82
-
83
- // Handle tvOS (non-Graphite only)
84
- if (!useGraphite) {
85
- try {
86
- const tvosPackage = path.dirname(
87
- require.resolve(prefix + "-apple-tvos/package.json")
88
- );
89
- console.log("-- Skia tvOS package: " + tvosPackage);
90
- fs.mkdirSync(path.join(libsDir, "tvos"), { recursive: true });
91
- copySync(tvosPackage + "/libs/*.xcframework", path.join(libsDir, "tvos"), {
92
- recursive: true,
93
- });
94
- } catch (e) {
95
- console.log("-- tvOS package not found, skipping");
96
- }
97
- }
98
-
99
- console.log("-- Copied Apple xcframeworks to libs/");
100
-
101
- // --- Android ---
102
-
103
- const androidPackageName = useGraphite
104
- ? "react-native-skia-graphite-android"
105
- : "react-native-skia-android";
106
-
107
- let androidPackage;
108
- try {
109
- androidPackage = path.dirname(
110
- require.resolve(androidPackageName + "/package.json")
111
- );
112
- } catch (e) {
113
- console.error("ERROR: Could not find " + androidPackageName);
114
- console.error("Make sure you have run yarn install or npm install");
115
- process.exit(1);
116
- }
117
-
118
- const androidSrcLibs = path.join(androidPackage, "libs");
119
- if (!fs.existsSync(androidSrcLibs)) {
120
- console.error(
121
- "ERROR: Skia prebuilt binaries not found in " + androidPackageName + "!"
122
- );
123
- process.exit(1);
124
- }
125
-
126
- console.log("-- Skia Android package: " + androidPackage);
127
-
128
- // Copy Android libs (per-ABI static libraries)
129
- const androidDest = path.join(libsDir, "android");
130
- fs.rmSync(androidDest, { recursive: true, force: true });
131
- copySync(androidSrcLibs, androidDest, { recursive: true });
132
-
133
- console.log("-- Copied Android libs to libs/android/");