blob: 776b84ae0bf88efed4cb4b8a7945abd5987277ed [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
#include <array>
#include <unordered_set>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cutils/properties.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
#include <gui/Surface.h>
#include <hardware/gralloc.h>
#include "DisplayHardware/DisplaySurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWC2.h"
#include "RenderEngine/RenderEngine.h"
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
#include "Layer.h"
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
namespace android {
// retrieve triple buffer setting from configstore
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using android::ui::ColorMode;
using android::ui::Dataspace;
using android::ui::Hdr;
using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
*
*/
uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
namespace {
// ordered list of known SDR color modes
const std::array<ColorMode, 2> sSdrColorModes = {
ColorMode::DISPLAY_P3,
ColorMode::SRGB,
};
// ordered list of known HDR color modes
const std::array<ColorMode, 2> sHdrColorModes = {
ColorMode::BT2100_PQ,
ColorMode::BT2100_HLG,
};
// ordered list of known SDR render intents
const std::array<RenderIntent, 2> sSdrRenderIntents = {
RenderIntent::ENHANCE,
RenderIntent::COLORIMETRIC,
};
// ordered list of known HDR render intents
const std::array<RenderIntent, 2> sHdrRenderIntents = {
RenderIntent::TONE_MAP_ENHANCE,
RenderIntent::TONE_MAP_COLORIMETRIC,
};
// map known color mode to dataspace
Dataspace colorModeToDataspace(ColorMode mode) {
switch (mode) {
case ColorMode::SRGB:
return Dataspace::SRGB;
case ColorMode::DISPLAY_P3:
return Dataspace::DISPLAY_P3;
case ColorMode::BT2100_HLG:
return Dataspace::BT2020_HLG;
case ColorMode::BT2100_PQ:
return Dataspace::BT2020_PQ;
default:
return Dataspace::UNKNOWN;
}
}
// Return a list of candidate color modes.
std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
std::vector<ColorMode> candidates;
// add mode itself
candidates.push_back(mode);
// check if mode is HDR
bool isHdr = false;
for (auto hdrMode : sHdrColorModes) {
if (hdrMode == mode) {
isHdr = true;
break;
}
}
// add other HDR candidates when mode is HDR
if (isHdr) {
for (auto hdrMode : sHdrColorModes) {
if (hdrMode != mode) {
candidates.push_back(hdrMode);
}
}
}
// add other SDR candidates
for (auto sdrMode : sSdrColorModes) {
if (sdrMode != mode) {
candidates.push_back(sdrMode);
}
}
return candidates;
}
// Return a list of candidate render intents.
std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
std::vector<RenderIntent> candidates;
// add intent itself
candidates.push_back(intent);
// check if intent is HDR
bool isHdr = false;
for (auto hdrIntent : sHdrRenderIntents) {
if (hdrIntent == intent) {
isHdr = true;
break;
}
}
if (isHdr) {
// add other HDR candidates when intent is HDR
for (auto hdrIntent : sHdrRenderIntents) {
if (hdrIntent != intent) {
candidates.push_back(hdrIntent);
}
}
} else {
// add other SDR candidates when intent is SDR
for (auto sdrIntent : sSdrRenderIntents) {
if (sdrIntent != intent) {
candidates.push_back(sdrIntent);
}
}
}
return candidates;
}
// Return the best color mode supported by HWC.
ColorMode getHwcColorMode(
const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
ColorMode mode) {
std::vector<ColorMode> candidates = getColorModeCandidates(mode);
for (auto candidate : candidates) {
auto iter = hwcColorModes.find(candidate);
if (iter != hwcColorModes.end()) {
return candidate;
}
}
return ColorMode::NATIVE;
}
// Return the best render intent supported by HWC.
RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
for (auto candidate : candidates) {
for (auto hwcIntent : hwcIntents) {
if (candidate == hwcIntent) {
return candidate;
}
}
}
return RenderIntent::COLORIMETRIC;
}
} // anonymous namespace
// clang-format off
DisplayDevice::DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
int32_t id,
bool isSecure,
const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<DisplaySurface>& displaySurface,
std::unique_ptr<RE::Surface> renderSurface,
int displayWidth,
int displayHeight,
bool hasWideColorGamut,
const HdrCapabilities& hdrCapabilities,
const int32_t supportedPerFrameMetadata,
const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
int initialPowerMode)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
mType(type),
mId(id),
mDisplayToken(displayToken),
mNativeWindow(nativeWindow),
mDisplaySurface(displaySurface),
mSurface{std::move(renderSurface)},
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
mPageFlipCount(0),
mIsSecure(isSecure),
mLayerStack(NO_LAYER_STACK),
mOrientation(),
mViewport(Rect::INVALID_RECT),
mFrame(Rect::INVALID_RECT),
mPowerMode(initialPowerMode),
mActiveConfig(0),
mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
mHasWideColorGamut(hasWideColorGamut),
mHasHdr10(false),
mHasHLG(false),
mHasDolbyVision(false),
mSupportedPerFrameMetadata(supportedPerFrameMetadata)
{
// clang-format on
populateColorModes(hwcColorModes);
std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes();
for (Hdr hdrType : types) {
switch (hdrType) {
case Hdr::HDR10:
mHasHdr10 = true;
break;
case Hdr::HLG:
mHasHLG = true;
break;
case Hdr::DOLBY_VISION:
mHasDolbyVision = true;
break;
default:
ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
}
}
float minLuminance = hdrCapabilities.getDesiredMinLuminance();
float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
float maxAverageLuminance = hdrCapabilities.getDesiredMaxAverageLuminance();
minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
if (this->hasWideColorGamut()) {
// insert HDR10/HLG as we will force client composition for HDR10/HLG
// layers
if (!hasHDR10Support()) {
types.push_back(Hdr::HDR10);
}
if (!hasHLGSupport()) {
types.push_back(Hdr::HLG);
}
}
mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}
DisplayDevice::~DisplayDevice() = default;
void DisplayDevice::disconnect(HWComposer& hwc) {
if (mId >= 0) {
hwc.disconnectDisplay(mId);
mId = -1;
}
}
bool DisplayDevice::isValid() const {
return mFlinger != nullptr;
}
int DisplayDevice::getWidth() const {
return mDisplayWidth;
}
int DisplayDevice::getHeight() const {
return mDisplayHeight;
}
void DisplayDevice::setDisplayName(const std::string& displayName) {
if (!displayName.empty()) {
// never override the name with an empty name
mDisplayName = displayName;
}
}
uint32_t DisplayDevice::getPageFlipCount() const {
return mPageFlipCount;
}
void DisplayDevice::flip() const
{
mFlinger->getRenderEngine().checkErrors();
mPageFlipCount++;
}
status_t DisplayDevice::beginFrame(bool mustRecompose) const {
return mDisplaySurface->beginFrame(mustRecompose);
}
status_t DisplayDevice::prepareFrame(HWComposer& hwc) {
status_t error = hwc.prepare(*this);
if (error != NO_ERROR) {
return error;
}
DisplaySurface::CompositionType compositionType;
bool hasClient = hwc.hasClientComposition(mId);
bool hasDevice = hwc.hasDeviceComposition(mId);
if (hasClient && hasDevice) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
} else if (hasClient) {
compositionType = DisplaySurface::COMPOSITION_GLES;
} else if (hasDevice) {
compositionType = DisplaySurface::COMPOSITION_HWC;
} else {
// Nothing to do -- when turning the screen off we get a frame like
// this. Call it a HWC frame since we won't be doing any GLES work but
// will do a prepare/set cycle.
compositionType = DisplaySurface::COMPOSITION_HWC;
}
return mDisplaySurface->prepareFrame(compositionType);
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
mSurface->swapBuffers();
}
status_t result = mDisplaySurface->advanceFrame();
if (result != NO_ERROR) {
ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
}
}
void DisplayDevice::onSwapBuffersCompleted() const {
mDisplaySurface->onFrameCommitted();
}
bool DisplayDevice::makeCurrent() const {
bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface);
setViewportAndProjection();
return success;
}
void DisplayDevice::setViewportAndProjection() const {
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
Rect sourceCrop(0, 0, w, h);
mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, h,
false, ui::Transform::ROT_0);
}
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
return mDisplaySurface->getClientTargetAcquireFence();
}
// ----------------------------------------------------------------------------
void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
mVisibleLayersSortedByZ = layers;
}
const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
return mVisibleLayersSortedByZ;
}
void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
mLayersNeedingFences = layers;
}
const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
return mLayersNeedingFences;
}
Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
Region dirty;
if (repaintEverything) {
dirty.set(getBounds());
} else {
const ui::Transform& planeTransform(mGlobalTransform);
dirty = planeTransform.transform(this->dirtyRegion);
dirty.andSelf(getBounds());
}
return dirty;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
}
int DisplayDevice::getPowerMode() const {
return mPowerMode;
}
bool DisplayDevice::isPoweredOn() const {
return mPowerMode != HWC_POWER_MODE_OFF;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setActiveConfig(int mode) {
mActiveConfig = mode;
}
int DisplayDevice::getActiveConfig() const {
return mActiveConfig;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setActiveColorMode(ColorMode mode) {
mActiveColorMode = mode;
}
ColorMode DisplayDevice::getActiveColorMode() const {
return mActiveColorMode;
}
RenderIntent DisplayDevice::getActiveRenderIntent() const {
return mActiveRenderIntent;
}
void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
mActiveRenderIntent = renderIntent;
}
void DisplayDevice::setColorTransform(const mat4& transform) {
const bool isIdentity = (transform == mat4());
mColorTransform =
isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
}
android_color_transform_t DisplayDevice::getColorTransform() const {
return mColorTransform;
}
void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
mCompositionDataSpace = dataspace;
ANativeWindow* const window = mNativeWindow.get();
native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDataSpace;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
mLayerStack = stack;
dirtyRegion.set(bounds());
}
// ----------------------------------------------------------------------------
uint32_t DisplayDevice::getOrientationTransform() const {
uint32_t transform = 0;
switch (mOrientation) {
case DisplayState::eOrientationDefault:
transform = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
transform = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
transform = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
transform = ui::Transform::ROT_270;
break;
}
return transform;
}
status_t DisplayDevice::orientationToTransfrom(
int orientation, int w, int h, ui::Transform* tr)
{
uint32_t flags = 0;
switch (orientation) {
case DisplayState::eOrientationDefault:
flags = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
flags = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
flags = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
flags = ui::Transform::ROT_270;
break;
default:
return BAD_VALUE;
}
tr->set(flags, w, h);
return NO_ERROR;
}
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
dirtyRegion.set(getBounds());
mSurface->setNativeWindow(nullptr);
mDisplaySurface->resizeBuffers(newWidth, newHeight);
ANativeWindow* const window = mNativeWindow.get();
mSurface->setNativeWindow(window);
mDisplayWidth = mSurface->queryWidth();
mDisplayHeight = mSurface->queryHeight();
LOG_FATAL_IF(mDisplayWidth != newWidth,
"Unable to set new width to %d", newWidth);
LOG_FATAL_IF(mDisplayHeight != newHeight,
"Unable to set new height to %d", newHeight);
}
void DisplayDevice::setProjection(int orientation,
const Rect& newViewport, const Rect& newFrame) {
Rect viewport(newViewport);
Rect frame(newFrame);
const int w = mDisplayWidth;
const int h = mDisplayHeight;
ui::Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
if (!frame.isValid()) {
// the destination frame can be invalid if it has never been set,
// in that case we assume the whole display frame.
frame = Rect(w, h);
}
if (viewport.isEmpty()) {
// viewport can be invalid if it has never been set, in that case
// we assume the whole display size.
// it's also invalid to have an empty viewport, so we handle that
// case in the same way.
viewport = Rect(w, h);
if (R.getOrientation() & ui::Transform::ROT_90) {
// viewport is always specified in the logical orientation
// of the display (ie: post-rotation).
std::swap(viewport.right, viewport.bottom);
}
}
dirtyRegion.set(getBounds());
ui::Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
float dst_width = frame.width();
float dst_height = frame.height();
if (src_width != dst_width || src_height != dst_height) {
float sx = dst_width / src_width;
float sy = dst_height / src_height;
S.set(sx, 0, 0, sy);
}
float src_x = viewport.left;
float src_y = viewport.top;
float dst_x = frame.left;
float dst_y = frame.top;
TL.set(-src_x, -src_y);
TP.set(dst_x, dst_y);
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
if (mType == DisplayType::DISPLAY_PRIMARY) {
int primaryDisplayOrientation = mFlinger->getPrimaryDisplayOrientation();
DisplayDevice::orientationToTransfrom(
(orientation + primaryDisplayOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
}
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
mGlobalTransform = R * TP * S * TL;
const uint8_t type = mGlobalTransform.getType();
mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
(type >= ui::Transform::SCALE));
mScissor = mGlobalTransform.transform(viewport);
if (mScissor.isEmpty()) {
mScissor = getBounds();
}
mOrientation = orientation;
if (isPrimary()) {
uint32_t transform = 0;
switch (mOrientation) {
case DisplayState::eOrientationDefault:
transform = ui::Transform::ROT_0;
break;
case DisplayState::eOrientation90:
transform = ui::Transform::ROT_90;
break;
case DisplayState::eOrientation180:
transform = ui::Transform::ROT_180;
break;
case DisplayState::eOrientation270:
transform = ui::Transform::ROT_270;
break;
}
sPrimaryDisplayOrientation = transform;
}
mViewport = viewport;
mFrame = frame;
}
uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
return sPrimaryDisplayOrientation;
}
void DisplayDevice::dump(String8& result) const {
const ui::Transform& tr(mGlobalTransform);
ANativeWindow* const window = mNativeWindow.get();
result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.c_str());
result.appendFormat(" type=%x, ID=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
"(%d:%d:%d:%d), orient=%2d (type=%08x), "
"flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
mType, mId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
mSurface->queryRedSize(), mSurface->queryGreenSize(),
mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size());
result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
auto const surface = static_cast<Surface*>(window);
ui::Dataspace dataspace = surface->getBuffersDataSpace();
result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
mHasWideColorGamut, mHasHdr10,
decodeColorMode(mActiveColorMode).c_str(),
dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
result.append(surfaceDump);
}
// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
// supported by HWC.
void DisplayDevice::addColorMode(
const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
const ColorMode mode, const RenderIntent intent) {
// find the best color mode
const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
// find the best render intent
auto iter = hwcColorModes.find(hwcColorMode);
const auto& hwcIntents =
iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
const Dataspace dataspace = colorModeToDataspace(mode);
const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mId,
dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
decodeRenderIntent(intent).c_str(),
dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
}
void DisplayDevice::populateColorModes(
const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) {
if (!hasWideColorGamut()) {
return;
}
// collect all known SDR render intents
std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
sSdrRenderIntents.end());
auto iter = hwcColorModes.find(ColorMode::SRGB);
if (iter != hwcColorModes.end()) {
for (auto intent : iter->second) {
sdrRenderIntents.insert(intent);
}
}
// add all known SDR combinations
for (auto intent : sdrRenderIntents) {
for (auto mode : sSdrColorModes) {
addColorMode(hwcColorModes, mode, intent);
}
}
// collect all known HDR render intents
std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
sHdrRenderIntents.end());
iter = hwcColorModes.find(ColorMode::BT2100_PQ);
if (iter != hwcColorModes.end()) {
for (auto intent : iter->second) {
hdrRenderIntents.insert(intent);
}
}
// add all known HDR combinations
for (auto intent : sHdrRenderIntents) {
for (auto mode : sHdrColorModes) {
addColorMode(hwcColorModes, mode, intent);
}
}
}
bool DisplayDevice::hasRenderIntent(RenderIntent intent) const {
// assume a render intent is supported when SRGB supports it; we should
// get rid of that assumption.
auto iter = mColorModes.find(getColorModeKey(Dataspace::SRGB, intent));
return iter != mColorModes.end() && iter->second.renderIntent == intent;
}
bool DisplayDevice::hasLegacyHdrSupport(Dataspace dataspace) const {
if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
(dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
auto iter =
mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
return iter == mColorModes.end() || iter->second.dataspace != dataspace;
}
return false;
}
void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent,
Dataspace* outDataspace, ColorMode* outMode,
RenderIntent* outIntent) const {
auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
if (iter != mColorModes.end()) {
*outDataspace = iter->second.dataspace;
*outMode = iter->second.colorMode;
*outIntent = iter->second.renderIntent;
} else {
ALOGE("map unknown (%s)/(%s) to default color mode",
dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
decodeRenderIntent(intent).c_str());
*outDataspace = Dataspace::UNKNOWN;
*outMode = ColorMode::NATIVE;
*outIntent = RenderIntent::COLORIMETRIC;
}
}
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android