react-native-webgpu 0.8.4 → 0.9.0
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.
- package/cpp/jsi/NativeObject.h +17 -12
- package/cpp/jsi/RuntimeAwareCache.cpp +1 -0
- package/cpp/jsi/RuntimeAwareCache.h +14 -0
- package/lib/commonjs/WebGPUViewNativeComponent.web.js +6 -49
- package/lib/commonjs/WebGPUViewNativeComponent.web.js.map +1 -1
- package/lib/module/WebGPUViewNativeComponent.web.js +5 -48
- package/lib/module/WebGPUViewNativeComponent.web.js.map +1 -1
- package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.web.d.ts.map +1 -1
- package/lib/typescript/lib/module/WebGPUViewNativeComponent.web.d.ts.map +1 -1
- package/lib/typescript/src/WebGPUViewNativeComponent.web.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/WebGPUViewNativeComponent.web.ts +4 -60
package/cpp/jsi/NativeObject.h
CHANGED
|
@@ -88,26 +88,31 @@ struct PrototypeCacheEntry {
|
|
|
88
88
|
*
|
|
89
89
|
* When used with static storage (like prototype caches), the cache persists
|
|
90
90
|
* across hot reloads. But the JSI objects inside become invalid when the
|
|
91
|
-
* runtime is destroyed. This wrapper tracks which runtime the
|
|
92
|
-
* created for and allocates a new cache when the
|
|
91
|
+
* runtime is destroyed. This wrapper tracks which main-runtime generation the
|
|
92
|
+
* cache was created for and allocates a new cache when the native module is
|
|
93
|
+
* reinstalled (RNWebGPUManager construction bumps the generation).
|
|
94
|
+
*
|
|
95
|
+
* The generation is used instead of the runtime pointer on purpose: on an
|
|
96
|
+
* in-process runtime recreate (expo-updates reloadAsync, DevSettings.reload)
|
|
97
|
+
* Hermes frequently allocates the new runtime at the address of the freed
|
|
98
|
+
* one. A pointer comparison then sees "same runtime", keeps the stale cache,
|
|
99
|
+
* and installConstructor() ends up touching a jsi::Object owned by the dead
|
|
100
|
+
* runtime (SIGSEGV in jsi::Value::~Value, see issue #461).
|
|
93
101
|
*
|
|
94
102
|
* The old cache is intentionally leaked - we cannot safely destroy JSI
|
|
95
103
|
* objects after their runtime is gone.
|
|
96
104
|
*/
|
|
97
105
|
template <typename T> struct StaticRuntimeAwareCache {
|
|
98
106
|
RuntimeAwareCache<T> *cache = nullptr;
|
|
99
|
-
|
|
107
|
+
uint64_t cacheGeneration = 0;
|
|
100
108
|
|
|
101
|
-
RuntimeAwareCache<T> &get(jsi::Runtime &rt) {
|
|
102
|
-
auto
|
|
103
|
-
if (
|
|
104
|
-
//
|
|
105
|
-
cache
|
|
106
|
-
cacheRuntime = mainRuntime;
|
|
107
|
-
}
|
|
108
|
-
if (cache == nullptr) {
|
|
109
|
+
RuntimeAwareCache<T> &get(jsi::Runtime & /*rt*/) {
|
|
110
|
+
auto generation = BaseRuntimeAwareCache::getMainJsRuntimeGeneration();
|
|
111
|
+
if (cache == nullptr || cacheGeneration != generation) {
|
|
112
|
+
// First use, or the main runtime was reinstalled (hot reload / OTA):
|
|
113
|
+
// allocate a fresh cache and leak the old one.
|
|
109
114
|
cache = new RuntimeAwareCache<T>();
|
|
110
|
-
|
|
115
|
+
cacheGeneration = generation;
|
|
111
116
|
}
|
|
112
117
|
return *cache;
|
|
113
118
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
#include <atomic>
|
|
6
6
|
#include <cassert>
|
|
7
|
+
#include <cstdint>
|
|
7
8
|
#include <memory>
|
|
8
9
|
#include <mutex>
|
|
9
10
|
#include <unordered_map>
|
|
@@ -21,6 +22,18 @@ public:
|
|
|
21
22
|
// Atomic: hot reload rewrites this from the JS thread while worklet
|
|
22
23
|
// runtime threads read it concurrently.
|
|
23
24
|
_mainRuntime.store(rt, std::memory_order_release);
|
|
25
|
+
// Every (re)installation of the native module starts a new generation.
|
|
26
|
+
// Callers that hold process-wide state derived from the main runtime
|
|
27
|
+
// (see StaticRuntimeAwareCache) must key their invalidation on this
|
|
28
|
+
// counter and NOT on the runtime pointer: when the JS runtime is
|
|
29
|
+
// destroyed and recreated in-process (expo-updates OTA apply,
|
|
30
|
+
// DevSettings.reload) the new jsi::Runtime is frequently allocated at
|
|
31
|
+
// the exact address of the freed one, so a pointer comparison cannot
|
|
32
|
+
// tell a reload from the steady state.
|
|
33
|
+
_mainRuntimeGeneration.fetch_add(1, std::memory_order_acq_rel);
|
|
34
|
+
}
|
|
35
|
+
static uint64_t getMainJsRuntimeGeneration() {
|
|
36
|
+
return _mainRuntimeGeneration.load(std::memory_order_acquire);
|
|
24
37
|
}
|
|
25
38
|
static jsi::Runtime *getMainJsRuntime() {
|
|
26
39
|
auto *rt = _mainRuntime.load(std::memory_order_acquire);
|
|
@@ -33,6 +46,7 @@ public:
|
|
|
33
46
|
|
|
34
47
|
private:
|
|
35
48
|
static std::atomic<jsi::Runtime *> _mainRuntime;
|
|
49
|
+
static std::atomic<uint64_t> _mainRuntimeGeneration;
|
|
36
50
|
};
|
|
37
51
|
|
|
38
52
|
/**
|
|
@@ -4,43 +4,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = WebGPUViewNativeComponent;
|
|
7
|
-
var _react =
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _utils = require("./utils");
|
|
10
|
-
function
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
-
function debounce(func, wait, immediate = false) {
|
|
13
|
-
let timeout;
|
|
14
|
-
return function debounced(...args) {
|
|
15
|
-
const context = this;
|
|
16
|
-
const callNow = immediate && !timeout;
|
|
17
|
-
if (timeout) {
|
|
18
|
-
clearTimeout(timeout);
|
|
19
|
-
}
|
|
20
|
-
timeout = setTimeout(() => {
|
|
21
|
-
timeout = undefined;
|
|
22
|
-
if (!immediate) {
|
|
23
|
-
func.apply(context, args);
|
|
24
|
-
}
|
|
25
|
-
}, wait);
|
|
26
|
-
if (callNow) {
|
|
27
|
-
func.apply(context, args);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function resizeCanvas(canvas) {
|
|
32
|
-
if (!canvas) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const dpr = window.devicePixelRatio || 1;
|
|
36
|
-
const {
|
|
37
|
-
height,
|
|
38
|
-
width
|
|
39
|
-
} = canvas.getBoundingClientRect();
|
|
40
|
-
canvas.setAttribute("height", (height * dpr).toString());
|
|
41
|
-
canvas.setAttribute("width", (width * dpr).toString());
|
|
42
|
-
}
|
|
43
|
-
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
44
11
|
// eslint-disable-next-line import/no-default-export
|
|
45
12
|
function WebGPUViewNativeComponent(props) {
|
|
46
13
|
const {
|
|
@@ -49,14 +16,10 @@ function WebGPUViewNativeComponent(props) {
|
|
|
49
16
|
transparent,
|
|
50
17
|
...rest
|
|
51
18
|
} = props;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return () => {
|
|
57
|
-
window.removeEventListener("resize", onResize);
|
|
58
|
-
};
|
|
59
|
-
}, []);
|
|
19
|
+
|
|
20
|
+
// MakeWebGPUCanvasContext sets the initial drawing-buffer size. Subsequent
|
|
21
|
+
// resizes belong to the renderer so it can recreate depth/MSAA attachments
|
|
22
|
+
// together; changing canvas.width/height here would invalidate its textures.
|
|
60
23
|
return /*#__PURE__*/_react.default.createElement("canvas", {
|
|
61
24
|
...rest,
|
|
62
25
|
id: (0, _utils.contextIdToId)(contextId),
|
|
@@ -67,12 +30,6 @@ function WebGPUViewNativeComponent(props) {
|
|
|
67
30
|
backgroundColor: "white"
|
|
68
31
|
} : {}),
|
|
69
32
|
...(typeof style === "object" ? style : {})
|
|
70
|
-
},
|
|
71
|
-
ref: ref => {
|
|
72
|
-
canvasElm.current = ref;
|
|
73
|
-
if (ref) {
|
|
74
|
-
resizeCanvas(ref);
|
|
75
|
-
}
|
|
76
33
|
}
|
|
77
34
|
});
|
|
78
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_utils","e","__esModule","default","WebGPUViewNativeComponent","props","contextId","style","transparent","rest","React","createElement","id","contextIdToId","styles","view","flex1","backgroundColor","StyleSheet","create","flex","alignItems","border","boxSizing","display","flexBasis","flexDirection","flexShrink","listStyle","margin","minHeight","minWidth","padding","position","zIndex"],"sourceRoot":"../../src","sources":["WebGPUViewNativeComponent.web.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAIA,IAAAE,MAAA,GAAAF,OAAA;AAAwC,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAOxC;AACe,SAASG,yBAAyBA,CAC/CC,KAAkB,EACC;EACnB,MAAM;IAAEC,SAAS;IAAEC,KAAK;IAAEC,WAAW;IAAE,GAAGC;EAAK,CAAC,GAAGJ,KAAK;;EAExD;EACA;EACA;EACA,oBAAOK,cAAK,CAACC,aAAa,CAAC,QAAQ,EAAE;IACnC,GAAGF,IAAI;IACPG,EAAE,EAAE,IAAAC,oBAAa,EAACP,SAAS,CAAC;IAC5BC,KAAK,EAAE;MACL,GAAGO,MAAM,CAACC,IAAI;MACd,GAAGD,MAAM,CAACE,KAAK;MACf,IAAIR,WAAW,KAAK,KAAK,GAAG;QAAES,eAAe,EAAE;MAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;MAC9D,IAAI,OAAOV,KAAK,KAAK,QAAQ,GAAGA,KAAK,GAAG,CAAC,CAAC;IAC5C;EACF,CAAC,CAAC;AACJ;AAEA,MAAMO,MAAM,GAAGI,uBAAU,CAACC,MAAM,CAAC;EAC/BH,KAAK,EAAE;IACLI,IAAI,EAAE;EACR,CAAC;EACDL,IAAI,EAAE;IACJM,UAAU,EAAE,SAAS;IACrBJ,eAAe,EAAE,aAAa;IAC9B;IACA;IACAK,MAAM,EAAE,eAAe;IACvBC,SAAS,EAAE,YAAY;IACvBC,OAAO,EAAE,MAAM;IACfC,SAAS,EAAE,MAAM;IACjBC,aAAa,EAAE,QAAQ;IACvBC,UAAU,EAAE,CAAC;IACbC,SAAS,EAAE,MAAM;IACjBC,MAAM,EAAE,CAAC;IACTC,SAAS,EAAE,CAAC;IACZC,QAAQ,EAAE,CAAC;IACXC,OAAO,EAAE,CAAC;IACVC,QAAQ,EAAE,UAAU;IACpBC,MAAM,EAAE;EACV;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,39 +1,6 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { StyleSheet } from "react-native";
|
|
3
3
|
import { contextIdToId } from "./utils";
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
-
function debounce(func, wait, immediate = false) {
|
|
6
|
-
let timeout;
|
|
7
|
-
return function debounced(...args) {
|
|
8
|
-
const context = this;
|
|
9
|
-
const callNow = immediate && !timeout;
|
|
10
|
-
if (timeout) {
|
|
11
|
-
clearTimeout(timeout);
|
|
12
|
-
}
|
|
13
|
-
timeout = setTimeout(() => {
|
|
14
|
-
timeout = undefined;
|
|
15
|
-
if (!immediate) {
|
|
16
|
-
func.apply(context, args);
|
|
17
|
-
}
|
|
18
|
-
}, wait);
|
|
19
|
-
if (callNow) {
|
|
20
|
-
func.apply(context, args);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function resizeCanvas(canvas) {
|
|
25
|
-
if (!canvas) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const dpr = window.devicePixelRatio || 1;
|
|
29
|
-
const {
|
|
30
|
-
height,
|
|
31
|
-
width
|
|
32
|
-
} = canvas.getBoundingClientRect();
|
|
33
|
-
canvas.setAttribute("height", (height * dpr).toString());
|
|
34
|
-
canvas.setAttribute("width", (width * dpr).toString());
|
|
35
|
-
}
|
|
36
|
-
|
|
37
4
|
// eslint-disable-next-line import/no-default-export
|
|
38
5
|
export default function WebGPUViewNativeComponent(props) {
|
|
39
6
|
const {
|
|
@@ -42,14 +9,10 @@ export default function WebGPUViewNativeComponent(props) {
|
|
|
42
9
|
transparent,
|
|
43
10
|
...rest
|
|
44
11
|
} = props;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return () => {
|
|
50
|
-
window.removeEventListener("resize", onResize);
|
|
51
|
-
};
|
|
52
|
-
}, []);
|
|
12
|
+
|
|
13
|
+
// MakeWebGPUCanvasContext sets the initial drawing-buffer size. Subsequent
|
|
14
|
+
// resizes belong to the renderer so it can recreate depth/MSAA attachments
|
|
15
|
+
// together; changing canvas.width/height here would invalidate its textures.
|
|
53
16
|
return /*#__PURE__*/React.createElement("canvas", {
|
|
54
17
|
...rest,
|
|
55
18
|
id: contextIdToId(contextId),
|
|
@@ -60,12 +23,6 @@ export default function WebGPUViewNativeComponent(props) {
|
|
|
60
23
|
backgroundColor: "white"
|
|
61
24
|
} : {}),
|
|
62
25
|
...(typeof style === "object" ? style : {})
|
|
63
|
-
},
|
|
64
|
-
ref: ref => {
|
|
65
|
-
canvasElm.current = ref;
|
|
66
|
-
if (ref) {
|
|
67
|
-
resizeCanvas(ref);
|
|
68
|
-
}
|
|
69
26
|
}
|
|
70
27
|
});
|
|
71
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","
|
|
1
|
+
{"version":3,"names":["React","StyleSheet","contextIdToId","WebGPUViewNativeComponent","props","contextId","style","transparent","rest","createElement","id","styles","view","flex1","backgroundColor","create","flex","alignItems","border","boxSizing","display","flexBasis","flexDirection","flexShrink","listStyle","margin","minHeight","minWidth","padding","position","zIndex"],"sourceRoot":"../../src","sources":["WebGPUViewNativeComponent.web.ts"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,QAAQ,cAAc;AAIzC,SAASC,aAAa,QAAQ,SAAS;AAOvC;AACA,eAAe,SAASC,yBAAyBA,CAC/CC,KAAkB,EACC;EACnB,MAAM;IAAEC,SAAS;IAAEC,KAAK;IAAEC,WAAW;IAAE,GAAGC;EAAK,CAAC,GAAGJ,KAAK;;EAExD;EACA;EACA;EACA,oBAAOJ,KAAK,CAACS,aAAa,CAAC,QAAQ,EAAE;IACnC,GAAGD,IAAI;IACPE,EAAE,EAAER,aAAa,CAACG,SAAS,CAAC;IAC5BC,KAAK,EAAE;MACL,GAAGK,MAAM,CAACC,IAAI;MACd,GAAGD,MAAM,CAACE,KAAK;MACf,IAAIN,WAAW,KAAK,KAAK,GAAG;QAAEO,eAAe,EAAE;MAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;MAC9D,IAAI,OAAOR,KAAK,KAAK,QAAQ,GAAGA,KAAK,GAAG,CAAC,CAAC;IAC5C;EACF,CAAC,CAAC;AACJ;AAEA,MAAMK,MAAM,GAAGV,UAAU,CAACc,MAAM,CAAC;EAC/BF,KAAK,EAAE;IACLG,IAAI,EAAE;EACR,CAAC;EACDJ,IAAI,EAAE;IACJK,UAAU,EAAE,SAAS;IACrBH,eAAe,EAAE,aAAa;IAC9B;IACA;IACAI,MAAM,EAAE,eAAe;IACvBC,SAAS,EAAE,YAAY;IACvBC,OAAO,EAAE,MAAM;IACfC,SAAS,EAAE,MAAM;IACjBC,aAAa,EAAE,QAAQ;IACvBC,UAAU,EAAE,CAAC;IACbC,SAAS,EAAE,MAAM;IACjBC,MAAM,EAAE,CAAC;IACTC,SAAS,EAAE,CAAC;IACZC,QAAQ,EAAE,CAAC;IACXC,OAAO,EAAE,CAAC;IACVC,QAAQ,EAAE,UAAU;IACpBC,MAAM,EAAE;EACV;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../commonjs/WebGPUViewNativeComponent.web.js"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../commonjs/WebGPUViewNativeComponent.web.js"],"names":[],"mappings":";;AAWA,4DAuBC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../module/WebGPUViewNativeComponent.web.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../module/WebGPUViewNativeComponent.web.js"],"names":[],"mappings":"AAIA,gHAuBC;kBA3BiB,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../src/WebGPUViewNativeComponent.web.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"WebGPUViewNativeComponent.web.d.ts","sourceRoot":"","sources":["../../../src/WebGPUViewNativeComponent.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,SAAS,EAAE,KAAK,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAGD,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAC/C,KAAK,EAAE,WAAW,GACjB,KAAK,CAAC,GAAG,CAAC,OAAO,CAgBnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-webgpu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "React Native WebGPU",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@expo/config-plugins": "^57.0.3",
|
|
71
|
-
"@semantic-release/commit-analyzer": "^13.0.
|
|
71
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
72
72
|
"@semantic-release/exec": "^7.0.3",
|
|
73
|
-
"@semantic-release/github": "^
|
|
74
|
-
"@semantic-release/release-notes-generator": "^14.
|
|
73
|
+
"@semantic-release/github": "^12.0.9",
|
|
74
|
+
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
75
75
|
"@types/jest": "^29.5.12",
|
|
76
76
|
"@types/node": "^20.14.7",
|
|
77
77
|
"@types/pixelmatch": "5.2.4",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"pixelmatch": "5.3.0",
|
|
93
93
|
"pngjs": "^7.0.0",
|
|
94
94
|
"prettier": "^3.0.3",
|
|
95
|
-
"puppeteer": "24.
|
|
95
|
+
"puppeteer": "24.43.1",
|
|
96
96
|
"react": "19.1.0",
|
|
97
97
|
"react-native": "0.81.4",
|
|
98
98
|
"react-native-builder-bob": "^0.23.2",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"react-native-worklets": "0.8.3",
|
|
102
102
|
"rimraf": "^5.0.7",
|
|
103
103
|
"seedrandom": "^3.0.5",
|
|
104
|
-
"semantic-release": "^
|
|
104
|
+
"semantic-release": "^25.0.9",
|
|
105
105
|
"semantic-release-yarn": "^3.0.2",
|
|
106
106
|
"teapot": "^1.0.0",
|
|
107
107
|
"tsx": "^4.20.5",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { StyleSheet } from "react-native";
|
|
3
3
|
import type { Int32 } from "react-native/Libraries/Types/CodegenTypes";
|
|
4
4
|
import type { ViewProps } from "react-native";
|
|
@@ -10,65 +10,15 @@ export interface NativeProps extends ViewProps {
|
|
|
10
10
|
transparent: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
-
function debounce<T extends (...args: any[]) => void>(
|
|
15
|
-
func: T,
|
|
16
|
-
wait: number,
|
|
17
|
-
immediate = false,
|
|
18
|
-
) {
|
|
19
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
20
|
-
return function debounced(
|
|
21
|
-
this: ThisParameterType<T>,
|
|
22
|
-
...args: Parameters<T>
|
|
23
|
-
) {
|
|
24
|
-
const context = this;
|
|
25
|
-
const callNow = immediate && !timeout;
|
|
26
|
-
if (timeout) {
|
|
27
|
-
clearTimeout(timeout);
|
|
28
|
-
}
|
|
29
|
-
timeout = setTimeout(() => {
|
|
30
|
-
timeout = undefined;
|
|
31
|
-
if (!immediate) {
|
|
32
|
-
func.apply(context, args);
|
|
33
|
-
}
|
|
34
|
-
}, wait);
|
|
35
|
-
if (callNow) {
|
|
36
|
-
func.apply(context, args);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function resizeCanvas(canvas: HTMLCanvasElement | null) {
|
|
42
|
-
if (!canvas) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const dpr = window.devicePixelRatio || 1;
|
|
47
|
-
|
|
48
|
-
const { height, width } = canvas.getBoundingClientRect();
|
|
49
|
-
canvas.setAttribute("height", (height * dpr).toString());
|
|
50
|
-
canvas.setAttribute("width", (width * dpr).toString());
|
|
51
|
-
}
|
|
52
|
-
|
|
53
13
|
// eslint-disable-next-line import/no-default-export
|
|
54
14
|
export default function WebGPUViewNativeComponent(
|
|
55
15
|
props: NativeProps,
|
|
56
16
|
): React.JSX.Element {
|
|
57
17
|
const { contextId, style, transparent, ...rest } = props;
|
|
58
18
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const onResize = debounce(
|
|
63
|
-
() => resizeCanvas(canvasElm.current ?? null),
|
|
64
|
-
100,
|
|
65
|
-
);
|
|
66
|
-
window.addEventListener("resize", onResize);
|
|
67
|
-
return () => {
|
|
68
|
-
window.removeEventListener("resize", onResize);
|
|
69
|
-
};
|
|
70
|
-
}, []);
|
|
71
|
-
|
|
19
|
+
// MakeWebGPUCanvasContext sets the initial drawing-buffer size. Subsequent
|
|
20
|
+
// resizes belong to the renderer so it can recreate depth/MSAA attachments
|
|
21
|
+
// together; changing canvas.width/height here would invalidate its textures.
|
|
72
22
|
return React.createElement("canvas", {
|
|
73
23
|
...rest,
|
|
74
24
|
id: contextIdToId(contextId),
|
|
@@ -78,12 +28,6 @@ export default function WebGPUViewNativeComponent(
|
|
|
78
28
|
...(transparent === false ? { backgroundColor: "white" } : {}),
|
|
79
29
|
...(typeof style === "object" ? style : {}),
|
|
80
30
|
},
|
|
81
|
-
ref: (ref: HTMLCanvasElement) => {
|
|
82
|
-
canvasElm.current = ref;
|
|
83
|
-
if (ref) {
|
|
84
|
-
resizeCanvas(ref);
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
31
|
});
|
|
88
32
|
}
|
|
89
33
|
|