react-native-wgpu 0.1.12 → 0.1.13
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/apple/ApplePlatformContext.h +19 -0
- package/apple/ApplePlatformContext.mm +86 -0
- package/apple/MetalView.h +13 -0
- package/apple/MetalView.mm +58 -0
- package/apple/WebGPUModule.h +19 -0
- package/apple/WebGPUModule.mm +93 -0
- package/apple/WebGPUView.h +15 -0
- package/apple/WebGPUView.mm +68 -0
- package/apple/WebGPUViewManager.mm +23 -0
- package/cpp/rnwgpu/api/Convertors.h +0 -9
- package/cpp/rnwgpu/api/GPUCanvasContext.cpp +6 -5
- package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +7 -0
- package/lib/typescript/src/__tests__/Alpha.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/Alpha.spec.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/Alpha.spec.ts +28 -0
- package/src/__tests__/snapshots/semi-opaque-cyan.png +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "PlatformContext.h"
|
|
4
|
+
|
|
5
|
+
namespace rnwgpu {
|
|
6
|
+
|
|
7
|
+
class ApplePlatformContext : public PlatformContext {
|
|
8
|
+
public:
|
|
9
|
+
ApplePlatformContext();
|
|
10
|
+
~ApplePlatformContext() = default;
|
|
11
|
+
|
|
12
|
+
wgpu::Surface makeSurface(wgpu::Instance instance, void *surface, int width,
|
|
13
|
+
int height) override;
|
|
14
|
+
|
|
15
|
+
ImageData createImageBitmap(std::string blobId, double offset,
|
|
16
|
+
double size) override;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#include "ApplePlatformContext.h"
|
|
2
|
+
|
|
3
|
+
#include <TargetConditionals.h>
|
|
4
|
+
|
|
5
|
+
#import <React/RCTBlobManager.h>
|
|
6
|
+
#import <React/RCTBridge+Private.h>
|
|
7
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
8
|
+
|
|
9
|
+
#include "RNWebGPUManager.h"
|
|
10
|
+
#include "WebGPUModule.h"
|
|
11
|
+
|
|
12
|
+
namespace rnwgpu {
|
|
13
|
+
|
|
14
|
+
void isSimulatorWithAPIValidation() {
|
|
15
|
+
#if TARGET_OS_SIMULATOR
|
|
16
|
+
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
|
|
17
|
+
NSString *metalDeviceWrapperType = environment[@"METAL_DEVICE_WRAPPER_TYPE"];
|
|
18
|
+
|
|
19
|
+
if ([metalDeviceWrapperType isEqualToString:@"1"]) {
|
|
20
|
+
throw std::runtime_error(
|
|
21
|
+
"To use React Native WebGPU project on the iOS simulator, you need to "
|
|
22
|
+
"disable the Metal validation API. In 'Edit Scheme,' uncheck 'Metal "
|
|
23
|
+
"Validation.'");
|
|
24
|
+
}
|
|
25
|
+
#endif
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ApplePlatformContext::ApplePlatformContext() { isSimulatorWithAPIValidation(); }
|
|
29
|
+
|
|
30
|
+
wgpu::Surface ApplePlatformContext::makeSurface(wgpu::Instance instance,
|
|
31
|
+
void *surface, int width,
|
|
32
|
+
int height) {
|
|
33
|
+
wgpu::SurfaceDescriptorFromMetalLayer metalSurfaceDesc;
|
|
34
|
+
metalSurfaceDesc.layer = surface;
|
|
35
|
+
wgpu::SurfaceDescriptor surfaceDescriptor;
|
|
36
|
+
surfaceDescriptor.nextInChain = &metalSurfaceDesc;
|
|
37
|
+
return instance.CreateSurface(&surfaceDescriptor);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ImageData ApplePlatformContext::createImageBitmap(std::string blobId,
|
|
41
|
+
double offset, double size) {
|
|
42
|
+
RCTBlobManager *blobManager =
|
|
43
|
+
[[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class];
|
|
44
|
+
NSData *blobData =
|
|
45
|
+
[blobManager resolve:[NSString stringWithUTF8String:blobId.c_str()]
|
|
46
|
+
offset:(long)offset
|
|
47
|
+
size:(long)size];
|
|
48
|
+
|
|
49
|
+
if (!blobData) {
|
|
50
|
+
throw std::runtime_error("Couldn't retrive blob data");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
UIImage *image = [UIImage imageWithData:blobData];
|
|
54
|
+
if (!image) {
|
|
55
|
+
throw std::runtime_error("Couldn't decode image");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
CGImageRef cgImage = image.CGImage;
|
|
59
|
+
size_t width = CGImageGetWidth(cgImage);
|
|
60
|
+
size_t height = CGImageGetHeight(cgImage);
|
|
61
|
+
size_t bitsPerComponent = 8;
|
|
62
|
+
size_t bytesPerRow = width * 4;
|
|
63
|
+
std::vector<uint8_t> imageData(height * bytesPerRow);
|
|
64
|
+
|
|
65
|
+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
66
|
+
CGContextRef context = CGBitmapContextCreate(
|
|
67
|
+
imageData.data(), width, height, bitsPerComponent, bytesPerRow,
|
|
68
|
+
colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
|
69
|
+
|
|
70
|
+
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
|
71
|
+
|
|
72
|
+
// Now imageData contains a copy of the bitmap data
|
|
73
|
+
|
|
74
|
+
CGContextRelease(context);
|
|
75
|
+
CGColorSpaceRelease(colorSpace);
|
|
76
|
+
|
|
77
|
+
// Use the copied data
|
|
78
|
+
ImageData result;
|
|
79
|
+
result.width = static_cast<int>(width);
|
|
80
|
+
result.height = static_cast<int>(height);
|
|
81
|
+
result.data = imageData;
|
|
82
|
+
result.format = wgpu::TextureFormat::RGBA8Unorm;
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#import "MetalView.h"
|
|
2
|
+
#import "webgpu_cpp.h"
|
|
3
|
+
|
|
4
|
+
#ifndef RCT_NEW_ARCH_ENABLED
|
|
5
|
+
#import <React/RCTViewManager.h>
|
|
6
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
7
|
+
|
|
8
|
+
@implementation MetalView {
|
|
9
|
+
BOOL _isConfigured;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
+ (Class)layerClass {
|
|
13
|
+
return [CAMetalLayer class];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (void)configure {
|
|
17
|
+
auto size = self.frame.size;
|
|
18
|
+
std::shared_ptr<rnwgpu::RNWebGPUManager> manager = [WebGPUModule getManager];
|
|
19
|
+
void *nativeSurface = (__bridge void *)self.layer;
|
|
20
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
21
|
+
auto gpu = manager->_gpu;
|
|
22
|
+
auto surface = manager->_platformContext->makeSurface(
|
|
23
|
+
gpu, nativeSurface, size.width, size.height);
|
|
24
|
+
registry
|
|
25
|
+
.getSurfaceInfoOrCreate([_contextId intValue], gpu, size.width,
|
|
26
|
+
size.height)
|
|
27
|
+
->switchToOnscreen(nativeSurface, surface);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
- (void)update {
|
|
31
|
+
auto size = self.frame.size;
|
|
32
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
33
|
+
registry.getSurfaceInfo([_contextId intValue])
|
|
34
|
+
->resize(size.width, size.height);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (void)dealloc {
|
|
38
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
39
|
+
// Remove the surface info from the registry
|
|
40
|
+
registry.removeSurfaceInfo([_contextId intValue]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#ifndef RCT_NEW_ARCH_ENABLED
|
|
44
|
+
// Paper only method
|
|
45
|
+
// TODO: this method is wrong, it appears to call configureSurface instead of
|
|
46
|
+
// updateSurface sometimes
|
|
47
|
+
- (void)reactSetFrame:(CGRect)frame {
|
|
48
|
+
[super reactSetFrame:frame];
|
|
49
|
+
if (!_isConfigured) {
|
|
50
|
+
[self configure];
|
|
51
|
+
_isConfigured = YES;
|
|
52
|
+
} else {
|
|
53
|
+
[self update];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
57
|
+
|
|
58
|
+
@end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import "RNWebGPUManager.h"
|
|
4
|
+
#import <React/RCTBridgeModule.h>
|
|
5
|
+
#import <React/RCTEventEmitter.h>
|
|
6
|
+
|
|
7
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
8
|
+
#import <RNWgpuViewSpec/RNWgpuViewSpec.h>
|
|
9
|
+
@interface WebGPUModule : RCTEventEmitter <NativeWebGPUModuleSpec>
|
|
10
|
+
#else
|
|
11
|
+
@interface WebGPUModule : RCTEventEmitter <RCTBridgeModule>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
@property(nonatomic, weak) RCTBridge *bridge;
|
|
15
|
+
@property(nonatomic, weak) RCTModuleRegistry *moduleRegistry;
|
|
16
|
+
|
|
17
|
+
+ (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager;
|
|
18
|
+
|
|
19
|
+
@end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#import "WebGPUModule.h"
|
|
2
|
+
#include "ApplePlatformContext.h"
|
|
3
|
+
#import "GPUCanvasContext.h"
|
|
4
|
+
|
|
5
|
+
#import <React/RCTBridge+Private.h>
|
|
6
|
+
#import <React/RCTLog.h>
|
|
7
|
+
#import <React/RCTUIManagerUtils.h>
|
|
8
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
9
|
+
#import <jsi/jsi.h>
|
|
10
|
+
#import <memory>
|
|
11
|
+
|
|
12
|
+
namespace jsi = facebook::jsi;
|
|
13
|
+
namespace react = facebook::react;
|
|
14
|
+
|
|
15
|
+
@implementation WebGPUModule
|
|
16
|
+
|
|
17
|
+
RCT_EXPORT_MODULE(WebGPUModule)
|
|
18
|
+
|
|
19
|
+
static std::shared_ptr<rnwgpu::RNWebGPUManager> webgpuManager;
|
|
20
|
+
|
|
21
|
+
+ (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager {
|
|
22
|
+
return webgpuManager;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#pragma Setup and invalidation
|
|
26
|
+
|
|
27
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
28
|
+
return YES;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (void)invalidate {
|
|
32
|
+
// if (_webgpuManager != nil) {
|
|
33
|
+
// [_webgpuManager invalidate];
|
|
34
|
+
// }
|
|
35
|
+
webgpuManager = nil;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
- (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager {
|
|
39
|
+
return webgpuManager;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
|
|
43
|
+
if (webgpuManager != nil) {
|
|
44
|
+
// Already initialized, ignore call.
|
|
45
|
+
return @true;
|
|
46
|
+
}
|
|
47
|
+
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)[RCTBridge currentBridge];
|
|
48
|
+
if (!cxxBridge.runtime) {
|
|
49
|
+
NSLog(@"Failed to install react-native-filament: RCTBridge is not a "
|
|
50
|
+
@"RCTCxxBridge!");
|
|
51
|
+
return [NSNumber numberWithBool:NO];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
jsi::Runtime *runtime = (jsi::Runtime *)cxxBridge.runtime;
|
|
55
|
+
if (!runtime) {
|
|
56
|
+
NSLog(@"Failed to install react-native-filament: jsi::Runtime* was null!");
|
|
57
|
+
return [NSNumber numberWithBool:NO];
|
|
58
|
+
}
|
|
59
|
+
std::shared_ptr<react::CallInvoker> jsInvoker = cxxBridge.jsCallInvoker;
|
|
60
|
+
if (!jsInvoker) {
|
|
61
|
+
NSLog(@"Failed to install react-native-filament: react::CallInvoker was "
|
|
62
|
+
@"null!");
|
|
63
|
+
return [NSNumber numberWithBool:NO];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!jsInvoker) {
|
|
67
|
+
jsInvoker = cxxBridge.jsCallInvoker;
|
|
68
|
+
}
|
|
69
|
+
std::shared_ptr<rnwgpu::PlatformContext> platformContext =
|
|
70
|
+
std::make_shared<rnwgpu::ApplePlatformContext>();
|
|
71
|
+
// TODO: remove allocation here
|
|
72
|
+
webgpuManager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime, jsInvoker,
|
|
73
|
+
platformContext);
|
|
74
|
+
return @true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(createSurfaceContext
|
|
78
|
+
// : (double)contextId) {
|
|
79
|
+
// int contextIdInt = contextId;
|
|
80
|
+
// RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
|
|
81
|
+
// auto runtime = (jsi::Runtime *)cxxBridge.runtime;
|
|
82
|
+
|
|
83
|
+
// return @true;
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
87
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
88
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
89
|
+
return std::make_shared<facebook::react::NativeWebGPUModuleSpecJSI>(params);
|
|
90
|
+
}
|
|
91
|
+
#endif
|
|
92
|
+
|
|
93
|
+
@end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#import "MetalView.h"
|
|
5
|
+
#import <React/RCTViewComponentView.h>
|
|
6
|
+
#import <UIKit/UIKit.h>
|
|
7
|
+
|
|
8
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
9
|
+
|
|
10
|
+
@interface WebGPUView : RCTViewComponentView
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_END
|
|
14
|
+
|
|
15
|
+
#endif /* RCT_NEW_ARCH_ENABLED */
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
#import "WebGPUView.h"
|
|
3
|
+
|
|
4
|
+
#import <react/renderer/components/RNWgpuViewSpec/ComponentDescriptors.h>
|
|
5
|
+
#import <react/renderer/components/RNWgpuViewSpec/EventEmitters.h>
|
|
6
|
+
#import <react/renderer/components/RNWgpuViewSpec/Props.h>
|
|
7
|
+
#import <react/renderer/components/RNWgpuViewSpec/RCTComponentViewHelpers.h>
|
|
8
|
+
|
|
9
|
+
#import "MetalView.h"
|
|
10
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
11
|
+
#import "Utils.h"
|
|
12
|
+
|
|
13
|
+
using namespace facebook::react;
|
|
14
|
+
|
|
15
|
+
@implementation WebGPUView
|
|
16
|
+
|
|
17
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
18
|
+
return concreteComponentDescriptorProvider<WebGPUViewComponentDescriptor>();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)prepareForRecycle {
|
|
22
|
+
[super prepareForRecycle];
|
|
23
|
+
/*
|
|
24
|
+
It's important to destroy the Metal Layer before releasing a view
|
|
25
|
+
to the recycled pool to prevent displaying outdated content from
|
|
26
|
+
the last usage in the new context.
|
|
27
|
+
*/
|
|
28
|
+
self.contentView = nil;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (MetalView *)getContentView {
|
|
32
|
+
if (!self.contentView) {
|
|
33
|
+
self.contentView = [MetalView new];
|
|
34
|
+
}
|
|
35
|
+
return (MetalView *)self.contentView;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
- (void)updateProps:(const Props::Shared &)props
|
|
39
|
+
oldProps:(const Props::Shared &)oldProps {
|
|
40
|
+
const auto &oldViewProps =
|
|
41
|
+
*std::static_pointer_cast<const WebGPUViewProps>(_props);
|
|
42
|
+
const auto &newViewProps =
|
|
43
|
+
*std::static_pointer_cast<const WebGPUViewProps>(props);
|
|
44
|
+
|
|
45
|
+
if (newViewProps.contextId != oldViewProps.contextId) {
|
|
46
|
+
/*
|
|
47
|
+
The context is set only once during mounting the component
|
|
48
|
+
and never changes because it isn't available for users to modify.
|
|
49
|
+
*/
|
|
50
|
+
MetalView *metalView = [MetalView new];
|
|
51
|
+
self.contentView = metalView;
|
|
52
|
+
[metalView setContextId:@(newViewProps.contextId)];
|
|
53
|
+
[metalView configure];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[super updateProps:props oldProps:oldProps];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
|
60
|
+
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
|
|
61
|
+
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
|
|
62
|
+
[(MetalView *)self.contentView update];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Class<RCTComponentViewProtocol> WebGPUViewCls(void) { return WebGPUView.class; }
|
|
66
|
+
|
|
67
|
+
@end
|
|
68
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#import "MetalView.h"
|
|
2
|
+
#import "RCTBridge.h"
|
|
3
|
+
#import "WebGPUModule.h"
|
|
4
|
+
#import <React/RCTUIManager.h>
|
|
5
|
+
#import <React/RCTViewManager.h>
|
|
6
|
+
|
|
7
|
+
@interface WebGPUViewManager : RCTViewManager
|
|
8
|
+
@end
|
|
9
|
+
|
|
10
|
+
@implementation WebGPUViewManager
|
|
11
|
+
|
|
12
|
+
RCT_EXPORT_MODULE(WebGPUView)
|
|
13
|
+
|
|
14
|
+
- (UIView *)view {
|
|
15
|
+
return [MetalView new];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
RCT_CUSTOM_VIEW_PROPERTY(contextId, NSNumber, UIView) {
|
|
19
|
+
NSNumber *contextId = [RCTConvert NSNumber:json];
|
|
20
|
+
[(MetalView *)view setContextId:contextId];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@end
|
|
@@ -280,15 +280,6 @@ public:
|
|
|
280
280
|
Convert(out.label, in.label);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
// [[nodiscard]] bool Convert(wgpu::CanvasConfiguration &out,
|
|
284
|
-
// const GPUCanvasConfiguration &in) {
|
|
285
|
-
// return Convert(out.device, in.device) && Convert(out.format, in.format)
|
|
286
|
-
// &&
|
|
287
|
-
// Convert(out.usage, in.usage) && Convert(out.viewFormats,
|
|
288
|
-
// in.viewFormats) && Convert(out.colorSpace, in.colorSpace) &&
|
|
289
|
-
// Convert(out.alphaMode, in.alphaMode);
|
|
290
|
-
// }
|
|
291
|
-
|
|
292
283
|
[[nodiscard]] bool Convert(wgpu::Color &out, const GPUColor &in) {
|
|
293
284
|
return Convert(out.r, in.r) && Convert(out.g, in.g) &&
|
|
294
285
|
Convert(out.b, in.b) && Convert(out.a, in.a);
|
|
@@ -16,12 +16,13 @@ void GPUCanvasContext::configure(
|
|
|
16
16
|
throw std::runtime_error("Error with SurfaceConfiguration");
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
if (!conv(surfaceConfiguration.format, configuration->format)) {
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
if (!conv(surfaceConfiguration.usage, configuration->usage)) {
|
|
23
|
-
throw std::runtime_error("Error with SurfaceConfiguration");
|
|
19
|
+
if (!conv(surfaceConfiguration.usage, configuration->usage) || !conv(surfaceConfiguration.format, configuration->format)) {
|
|
20
|
+
throw std::runtime_error("Error with SurfaceConfiguration");
|
|
24
21
|
}
|
|
22
|
+
|
|
23
|
+
#ifdef __APPLE__
|
|
24
|
+
surfaceConfiguration.alphaMode = configuration->alphaMode;
|
|
25
|
+
#endif
|
|
25
26
|
_surfaceInfo->configure(surfaceConfiguration);
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -21,6 +21,7 @@ struct GPUCanvasConfiguration {
|
|
|
21
21
|
std::optional<double> usage; // GPUTextureUsageFlags
|
|
22
22
|
std::optional<std::vector<wgpu::TextureFormat>>
|
|
23
23
|
viewFormats; // Iterable<GPUTextureFormat>
|
|
24
|
+
wgpu::CompositeAlphaMode alphaMode = wgpu::CompositeAlphaMode::Opaque;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
} // namespace rnwgpu
|
|
@@ -58,6 +59,12 @@ struct JSIConverter<std::shared_ptr<rnwgpu::GPUCanvasConfiguration>> {
|
|
|
58
59
|
prop,
|
|
59
60
|
false);
|
|
60
61
|
}
|
|
62
|
+
if (value.hasProperty(runtime, "alphaMode")) {
|
|
63
|
+
auto prop = value.getProperty(runtime, "alphaMode").asString(runtime).utf8(runtime);
|
|
64
|
+
if (prop == "premultiplied") {
|
|
65
|
+
result->alphaMode = wgpu::CompositeAlphaMode::Premultiplied;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
return result;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Alpha.spec.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/Alpha.spec.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-wgpu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "React Native WebGPU",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"android/cpp/**",
|
|
16
16
|
"android/src/**",
|
|
17
17
|
"cpp/**/*.{h,cpp}",
|
|
18
|
-
"
|
|
18
|
+
"apple/**",
|
|
19
19
|
"libs/**",
|
|
20
20
|
"*.podspec"
|
|
21
21
|
],
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { checkImage, client, encodeImage } from "./setup";
|
|
2
|
+
|
|
3
|
+
describe("Alpha", () => {
|
|
4
|
+
it("Premultiplied Color", async () => {
|
|
5
|
+
const result = await client.eval(({ device, ctx, canvas }) => {
|
|
6
|
+
const commandEncoder = device.createCommandEncoder();
|
|
7
|
+
const textureView = ctx.getCurrentTexture().createView();
|
|
8
|
+
const alpha = 0.5;
|
|
9
|
+
const renderPassDescriptor: GPURenderPassDescriptor = {
|
|
10
|
+
colorAttachments: [
|
|
11
|
+
{
|
|
12
|
+
view: textureView,
|
|
13
|
+
clearValue: [0.3 * alpha, 0.6 * alpha, 1 * alpha, alpha],
|
|
14
|
+
loadOp: "clear",
|
|
15
|
+
storeOp: "store",
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
21
|
+
passEncoder.end();
|
|
22
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
23
|
+
return canvas.getImageData();
|
|
24
|
+
});
|
|
25
|
+
const image = encodeImage(result);
|
|
26
|
+
checkImage(image, "snapshots/semi-opaque-cyan.png");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
Binary file
|