Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/apple-sdks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: apple-sdks
on:
push:
branches:
- main
pull_request:
paths:
- "packages/webgpu/apple/**"
- "packages/webgpu/cpp/**"
- "packages/webgpu/package.json"
- "packages/webgpu/scripts/check-apple-sdks.sh"
- ".github/workflows/apple-sdks.yml"
jobs:
apple-sdks:
# Syntax-check only: no yarn install, no pods, no simulator. Only the Dawn
# headers are downloaded (about 1 MB out of the package's tarball).
runs-on: macos-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Download Dawn headers
run: |
VERSION=$(node -p 'require("./packages/webgpu/package.json").dependencies["react-native-webgpu-dawn"]')
mkdir -p "$RUNNER_TEMP/dawn"
curl -sfL "https://registry.npmjs.org/react-native-webgpu-dawn/-/react-native-webgpu-dawn-$VERSION.tgz" \
| tar xz -C "$RUNNER_TEMP/dawn" package/include
- name: Check Apple sources against every SDK
run: packages/webgpu/scripts/check-apple-sdks.sh "$RUNNER_TEMP/dawn/package/include"
2 changes: 1 addition & 1 deletion apps/docs/content/api/canvas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ To show the views behind the canvas, configure the context with `alphaMode: "pre

## HDR (extended dynamic range)

`context.configure({ toneMapping: { mode } })` says what happens to values above 1.0 on an `rgba16float` canvas: `"standard"` (the default) clamps them to the display's SDR range, `"extended"` lets them use the display's headroom, as in a browser. On iOS 16 and later the `CAMetalLayer` opts into extended dynamic range content for `"extended"`; the mode is accepted and has no effect on an 8-bit canvas, which cannot hold values above 1.0. Android currently ignores `toneMapping`.
`context.configure({ toneMapping: { mode } })` says what happens to values above 1.0 on an `rgba16float` canvas: `"standard"` (the default) clamps them to the display's SDR range, `"extended"` lets them use the display's headroom, as in a browser. On iOS 16 and later the `CAMetalLayer` opts into extended dynamic range content for `"extended"`; the mode is accepted and has no effect on an 8-bit canvas, which cannot hold values above 1.0. tvOS has no extended dynamic range for this layer, so `"extended"` behaves like `"standard"` there. Android currently ignores `toneMapping`.

### Android rendering options

Expand Down
32 changes: 21 additions & 11 deletions packages/webgpu/apple/AppleVideoPlayer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ static int rotationFromTransform(CGAffineTransform t) {
// The metadata loads asynchronously, so that a remote asset never blocks
// the calling thread; the getters report 0 until it has.
AVAsset *asset = item.asset;
void (^readVideoTrack)(AVAssetTrack *) = ^(AVAssetTrack *track) {
if (track) {
CGSize size = track.naturalSize;
state->width = static_cast<uint32_t>(size.width);
state->height = static_cast<uint32_t>(size.height);
state->rotation = rotationFromTransform(track.preferredTransform);
state->frameRate = track.nominalFrameRate;
}
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[asset
Expand All @@ -155,17 +164,18 @@ static int rotationFromTransform(CGAffineTransform t) {
}
if ([asset statusOfValueForKey:@"tracks" error:nil] ==
AVKeyValueStatusLoaded) {
AVAssetTrack *track =
[[asset tracksWithMediaType:AVMediaTypeVideo]
firstObject];
if (track) {
CGSize size = track.naturalSize;
state->width = static_cast<uint32_t>(size.width);
state->height = static_cast<uint32_t>(size.height);
state->rotation =
rotationFromTransform(track.preferredTransform);
state->frameRate = track.nominalFrameRate;
}
#if TARGET_OS_VISION
// tracksWithMediaType: is unavailable on visionOS.
[asset loadTracksWithMediaType:AVMediaTypeVideo
completionHandler:^(
NSArray<AVAssetTrack *> *tracks,
NSError * /*error*/) {
readVideoTrack(tracks.firstObject);
}];
#else
readVideoTrack(
[[asset tracksWithMediaType:AVMediaTypeVideo] firstObject]);
#endif
}
}];
#pragma clang diagnostic pop
Expand Down
9 changes: 8 additions & 1 deletion packages/webgpu/apple/MetalLayerColorSpace.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,18 @@ void applyCAMetalLayerColorSpace(void *nativeSurface,
}
const bool extendedRange =
isFloat && toneMappingMode == CanvasToneMappingMode::Extended;
if (@available(iOS 16.0, tvOS 16.0, *)) {
// The property does not exist on tvOS (the SDK marks it unavailable, which
// @available cannot work around), so it is compiled only where it exists.
// On tvOS "extended" behaves like "standard".
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION
if (@available(iOS 16.0, macOS 10.11, visionOS 1.0, *)) {
if (metalLayer.wantsExtendedDynamicRangeContent != extendedRange) {
metalLayer.wantsExtendedDynamicRangeContent = extendedRange;
}
}
#else
(void)extendedRange;
#endif
// The change must be set synchronously so the first present already sees
// it, and it must reach the render server. On a non-main thread (RN JS or
// worklet runtime) the property lands in that thread's implicit
Expand Down
48 changes: 48 additions & 0 deletions packages/webgpu/scripts/check-apple-sdks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Syntax-checks the Apple sources that compile without React headers against
# every Apple SDK the package can be built for. An API that exists on iOS but
# is marked unavailable on another platform (wantsExtendedDynamicRangeContent
# on tvOS, #606) is a compile error that @available cannot hide, and nothing
# else in CI builds for tvOS or visionOS.
#
# Usage: check-apple-sdks.sh [dawn-include-dir]
# Defaults to the Dawn headers installed in node_modules.
set -euo pipefail

cd "$(dirname "$0")/.."

DAWN_INCLUDE="${1:-}"
if [ -z "$DAWN_INCLUDE" ]; then
DAWN_INCLUDE="$(dirname "$(node -p 'require.resolve("react-native-webgpu-dawn/package.json")')")/include"
fi

# The other files under apple/ need React and codegen headers, which only
# exist after a pod install.
FILES=(apple/MetalLayerColorSpace.mm apple/AppleVideoPlayer.mm)

# sdk:target pairs, using the podspec's minimum versions.
TARGETS=(
iphoneos:arm64-apple-ios15.1
iphonesimulator:arm64-apple-ios15.1-simulator
macosx:arm64-apple-macos10.15
xros:arm64-apple-xros1.0
appletvos:arm64-apple-tvos15.1
appletvsimulator:arm64-apple-tvos15.1-simulator
)

status=0
for pair in "${TARGETS[@]}"; do
sdk="${pair%%:*}"
target="${pair#*:}"
for file in "${FILES[@]}"; do
if xcrun --sdk "$sdk" clang++ -target "$target" -std=c++20 -fobjc-arc \
-fsyntax-only -w -x objective-c++ -I "$DAWN_INCLUDE" -I cpp/rnwgpu \
-I cpp -I apple "$file"; then
echo "✅ $sdk $file"
else
echo "❌ $sdk $file"
status=1
fi
done
done
exit $status
Loading