| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/paint/tone_map_util.h" |
| |
| #include <cmath> |
| #include <memory> |
| #include <string_view> |
| #include <utility> |
| |
| #include "cc/paint/paint_image.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkColorFilter.h" |
| #include "third_party/skia/include/core/SkColorSpace.h" |
| #include "third_party/skia/include/core/SkPaint.h" |
| #include "third_party/skia/include/effects/SkColorMatrix.h" |
| #include "third_party/skia/include/effects/SkRuntimeEffect.h" |
| #include "third_party/skia/include/private/SkHdrMetadata.h" |
| #include "ui/gfx/hdr_metadata.h" |
| |
| namespace cc { |
| |
| bool ToneMapUtil::UseGlobalToneMapFilter(const SkImage* image, |
| const gfx::HDRMetadata& metadata, |
| const SkColorSpace* dst_color_space) { |
| if (!image) { |
| return false; |
| } |
| // Workaround for crbug.com/337538021: Disable tone mapping when the source |
| // and destination spaces are the same, to avoid applying tone mapping when |
| // uploading HLG or PQ frames to textures. |
| if (SkColorSpace::Equals(image->colorSpace(), dst_color_space)) { |
| return false; |
| } |
| return UseGlobalToneMapFilter(image->colorSpace(), metadata); |
| } |
| |
| bool ToneMapUtil::UseGlobalToneMapFilter(const SkColorSpace* cs, |
| const gfx::HDRMetadata& metadata) { |
| if (!cs) { |
| return false; |
| } |
| skcms_TransferFunction fn; |
| cs->transferFn(&fn); |
| if (skcms_TransferFunction_isHLGish(&fn) || |
| skcms_TransferFunction_isPQish(&fn) || |
| skcms_TransferFunction_isHLG(&fn) || skcms_TransferFunction_isPQ(&fn)) { |
| return true; |
| } |
| if (metadata.HasAgtm()) { |
| if (auto& hatm = metadata.GetAgtm().fHeadroomAdaptiveToneMap) { |
| if (!hatm->fAlternateImages.empty()) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void ToneMapUtil::AddGlobalToneMapFilterToPaint( |
| SkPaint& paint, |
| const SkImage* image, |
| const gfx::HDRMetadata& metadata, |
| float target_hdr_headroom) { |
| if (!image || !image->colorSpace()) { |
| return; |
| } |
| |
| skhdr::Metadata skia_metadata; |
| |
| // Parse AGTM only if the feature is enabled. |
| skhdr::AdaptiveGlobalToneMap agtm; |
| bool agtm_valid = false; |
| if (gfx::HdrMetadataAgtm::IsEnabled() && metadata.HasAgtm()) { |
| agtm_valid = true; |
| agtm = metadata.GetAgtm(); |
| } |
| |
| // Use NDWL to specify HDR reference white only if AGTM was not present. |
| if (!agtm_valid && metadata.HasNDWL() && metadata.GetNDWL() > 0.f) { |
| agtm.fHdrReferenceWhite = metadata.GetNDWL(); |
| agtm_valid = true; |
| } |
| |
| // Set the MDCV, CLLI, and AGTM values on `skia_metadata`. |
| if (metadata.HasMDCV()) { |
| skia_metadata.setMasteringDisplayColorVolume(metadata.GetMDCV()); |
| } |
| if (metadata.HasCLLI()) { |
| skia_metadata.setContentLightLevelInformation(metadata.GetCLLI()); |
| } |
| if (agtm_valid) { |
| skia_metadata.setAdaptiveGlobalToneMap(agtm); |
| } |
| |
| // Use skhdr::Metadata to compute the filter. |
| auto tone_map_filter = skia_metadata.makeToneMapColorFilter( |
| target_hdr_headroom, image->colorSpace()); |
| |
| // Perform the original filter after tone mapping. |
| if (tone_map_filter) { |
| paint.setColorFilter(SkColorFilters::Compose(paint.refColorFilter(), |
| std::move(tone_map_filter))); |
| } |
| } |
| |
| } // namespace cc |