Support capturing a gainmapped screenshot
This uses the gainmap concept from UltraHDR and ISO 21496-1 to produce
screenshots that (a) can be rendered in HDR and (b) that are perfectly
backwards-compatible on SDR displays are scenes where displaying SDR is
preferable.
The technical details of the screenshot process at a high level are:
* A client requests that they want a gainmap attached to the screenshot
result
* SurfaceFlinger asks RenderEngine to perform three render passes
* First, render the SDR base image, tonemapping using MouriMap
* Second, render an HDR rendition. This is *also* tonemapped using
MouriMap to the current display conditions. For HDR UI, this is
effectively a no-op. For PQ and HLG content, this allows for
approximating what is on-screen as closely as possible. Note that
to preserve precision as much as possible, we require an FP16
framebuffer.
* Finally, combine the SDR and HDR renditions into a gainmap
* The client now receives the base image with the gainmap, as well as an
HDR/SDR ratio. The client can use this information to generate gainmap
metadata for encoding or round-tripping to the display.
This MVP is sufficient for generating screenshots through adb screencap.
Eventually, this can be used to integrate with the applications that
want HDR screenshots, or to remove hacks that disable tonemapping during
certain system animations.
Bug: 329470026
Flag: com.android.graphics.surfaceflinger.flags.true_hdr_screenshots
Test: builds
Test: adb screencap
Change-Id: I0434059d957bb6cc38d019743619d72dda72a269
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 7712d38..06c2f26 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -346,6 +346,7 @@
constexpr bool kRegionSampling = true;
constexpr bool kGrayscale = false;
constexpr bool kIsProtected = false;
+ constexpr bool kAttachGainmap = false;
SurfaceFlinger::RenderAreaBuilderVariant
renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds,
@@ -358,15 +359,15 @@
std::vector<sp<LayerFE>> layerFEs;
auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder,
getLayerSnapshotsFn, layerFEs);
- fenceResult =
- mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale,
- kIsProtected, nullptr, displayState, layerFEs)
- .get();
+ fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling,
+ kGrayscale, kIsProtected, kAttachGainmap, nullptr,
+ displayState, layerFEs)
+ .get();
} else {
- fenceResult =
- mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, buffer,
- kRegionSampling, kGrayscale, kIsProtected, nullptr)
- .get();
+ fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn,
+ buffer, kRegionSampling, kGrayscale,
+ kIsProtected, kAttachGainmap, nullptr)
+ .get();
}
if (fenceResult.ok()) {
fenceResult.value()->waitForever(LOG_TAG);