fix(apple/tvOS): guard EDR HDR APIs unavailable on tvOS
apple / swift (push) Successful in 1m12s
release / apple (push) Successful in 9m11s
apple / screenshots (push) Successful in 4m49s
ci / web (push) Successful in 1m1s
ci / docs-site (push) Successful in 1m19s
ci / rust (push) Successful in 4m45s
deb / build-publish (push) Successful in 3m11s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
ci / bench (push) Successful in 6m51s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m55s
docker / deploy-docs (push) Successful in 5s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m49s
android / android (push) Successful in 3m10s
apple / swift (push) Successful in 1m12s
release / apple (push) Successful in 9m11s
apple / screenshots (push) Successful in 4m49s
ci / web (push) Successful in 1m1s
ci / docs-site (push) Successful in 1m19s
ci / rust (push) Successful in 4m45s
deb / build-publish (push) Successful in 3m11s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
ci / bench (push) Successful in 6m51s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m55s
docker / deploy-docs (push) Successful in 5s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m49s
android / android (push) Successful in 3m10s
The tvOS archive failed compiling PunktfunkKit: a recent presenter HDR change dropped the `#if os(macOS)` guard around the EDR calls and applied them "on all platforms", but `wantsExtendedDynamicRangeContent`, `CAEDRMetadata`, and `CAMetalLayer.edrMetadata` are all explicitly unavailable on tvOS. Wrap the EDR usage (and the makeEDR helper, whose return type is the unavailable CAEDRMetadata) in `#if !os(tvOS)`. macOS + iOS keep the reference-white-anchored EDR path unchanged; tvOS now sets only the rgba16Float pixel format + itur_2100_PQ colour space and lets its compositor tone-map from those. The 0xCE grade is still cached on tvOS (harmless), it just can't be pushed to the layer there. tvOS Simulator build: BUILD SUCCEEDED (PunktfunkKit Swift compile, the step that failed). macOS build + test green (49 tests); iOS compiles clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -223,32 +223,39 @@ public final class MetalVideoPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the layer's pixel format + colour config for SDR or HDR. MAIN THREAD ONLY. EDR is requested
|
/// Set the layer's pixel format + colour config for SDR or HDR. MAIN THREAD ONLY. EDR is requested
|
||||||
/// on ALL platforms — the property is available on macOS/iOS/tvOS at our deployment floor, and the
|
/// on macOS + iOS (the old `#if os(macOS)` guard left iOS EDR half-engaged). tvOS has NO EDR API
|
||||||
/// old `#if os(macOS)` guard left iOS/tvOS EDR half-engaged.
|
/// (`wantsExtendedDynamicRangeContent`/`edrMetadata`/`CAEDRMetadata` are all unavailable there), so
|
||||||
|
/// it gets the PQ pixel format + colour space only — the tvOS compositor tone-maps from those.
|
||||||
private func configureColor(hdr: Bool) {
|
private func configureColor(hdr: Bool) {
|
||||||
if hdr {
|
if hdr {
|
||||||
layer.pixelFormat = .rgba16Float
|
layer.pixelFormat = .rgba16Float
|
||||||
layer.colorspace = CGColorSpace(name: CGColorSpace.itur_2100_PQ)
|
layer.colorspace = CGColorSpace(name: CGColorSpace.itur_2100_PQ)
|
||||||
|
#if !os(tvOS)
|
||||||
layer.wantsExtendedDynamicRangeContent = true
|
layer.wantsExtendedDynamicRangeContent = true
|
||||||
// Anchor reference white. Re-apply the real grade if one already arrived (0xCE before the
|
// Anchor reference white. Re-apply the real grade if one already arrived (0xCE before the
|
||||||
// flip); otherwise the bare 203-nit anchor. Without this anchor the PQ signal is too bright.
|
// flip); otherwise the bare 203-nit anchor. Without this anchor the PQ signal is too bright.
|
||||||
layer.edrMetadata = makeEDR(lastHdrMeta)
|
layer.edrMetadata = makeEDR(lastHdrMeta)
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// SDR: gamma-encoded BT.709 [0,1] in an 8-bit drawable; a nil colorspace tags it device/sRGB
|
// SDR: gamma-encoded BT.709 [0,1] in an 8-bit drawable; a nil colorspace tags it device/sRGB
|
||||||
// (the proven SDR path — never showed the "too bright" issue, which was HDR-only).
|
// (the proven SDR path — never showed the "too bright" issue, which was HDR-only).
|
||||||
layer.pixelFormat = .bgra8Unorm
|
layer.pixelFormat = .bgra8Unorm
|
||||||
layer.colorspace = nil
|
layer.colorspace = nil
|
||||||
|
#if !os(tvOS)
|
||||||
layer.wantsExtendedDynamicRangeContent = false
|
layer.wantsExtendedDynamicRangeContent = false
|
||||||
layer.edrMetadata = nil
|
layer.edrMetadata = nil
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
private func makeEDR(_ meta: PunktfunkConnection.HdrMeta?) -> CAEDRMetadata {
|
private func makeEDR(_ meta: PunktfunkConnection.HdrMeta?) -> CAEDRMetadata {
|
||||||
CAEDRMetadata.hdr10(
|
CAEDRMetadata.hdr10(
|
||||||
displayInfo: meta?.masteringDisplayColorVolume(),
|
displayInfo: meta?.masteringDisplayColorVolume(),
|
||||||
contentInfo: meta?.contentLightLevelInfo(),
|
contentInfo: meta?.contentLightLevelInfo(),
|
||||||
opticalOutputScale: hdrReferenceWhiteNits)
|
opticalOutputScale: hdrReferenceWhiteNits)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Update the HDR mastering metadata (drained from the host's 0xCE datagram) to refine the system
|
/// Update the HDR mastering metadata (drained from the host's 0xCE datagram) to refine the system
|
||||||
/// tone-map from the real grade. Called from the PUMP thread, so the layer write is hopped to MAIN
|
/// tone-map from the real grade. Called from the PUMP thread, so the layer write is hopped to MAIN
|
||||||
@@ -259,7 +266,11 @@ public final class MetalVideoPresenter {
|
|||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
self.lastHdrMeta = meta
|
self.lastHdrMeta = meta
|
||||||
|
// tvOS has no edrMetadata — the cached grade is still kept above (harmless), it just can't
|
||||||
|
// be applied to the layer there. macOS/iOS refine the system tone-map from the real grade.
|
||||||
|
#if !os(tvOS)
|
||||||
if self.hdrActive { self.layer.edrMetadata = self.makeEDR(meta) }
|
if self.hdrActive { self.layer.edrMetadata = self.makeEDR(meta) }
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user