blob: 74310910801546ccc9fb1aea79b62fba3554b85f [file] [log] [blame]
/*
* Copyright (C) 2020 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.
*/
#include "BrightnessController.h"
#include "ExynosDisplayDrmInterfaceModule.h"
#include "ExynosPrimaryDisplayModule.h"
#include <drm/samsung_drm.h>
using BrightnessRange = BrightnessController::BrightnessRange;
using namespace gs101;
/////////////////////////////////////////////////// ExynosDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosDisplayDrmInterfaceModule::ExynosDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
: ExynosDisplayDrmInterface(exynosDisplay)
{
}
ExynosDisplayDrmInterfaceModule::~ExynosDisplayDrmInterfaceModule()
{
}
void ExynosDisplayDrmInterfaceModule::parseBpcEnums(const DrmProperty& property)
{
const std::vector<std::pair<uint32_t, const char *>> bpcEnums = {
{static_cast<uint32_t>(BPC_UNSPECIFIED), "Unspecified"},
{static_cast<uint32_t>(BPC_8), "8bpc"},
{static_cast<uint32_t>(BPC_10), "10bpc"},
};
ALOGD("Init bpc enums");
DrmEnumParser::parseEnums(property, bpcEnums, mBpcEnums);
for (auto &e : mBpcEnums) {
ALOGD("bpc [bpc: %d, drm: %" PRId64 "]", e.first, e.second);
}
}
int32_t ExynosDisplayDrmInterfaceModule::initDrmDevice(DrmDevice *drmDevice)
{
int ret = NO_ERROR;
if ((ret = ExynosDisplayDrmInterface::initDrmDevice(drmDevice)) != NO_ERROR)
return ret;
mOldDqeBlobs.init(drmDevice);
initOldDppBlobs(drmDevice);
if (mDrmCrtc->force_bpc_property().id())
parseBpcEnums(mDrmCrtc->force_bpc_property());
mOldHistoBlobs.init(drmDevice);
return ret;
}
void ExynosDisplayDrmInterfaceModule::destroyOldBlobs(
std::vector<uint32_t> &oldBlobs)
{
for (auto &blob : oldBlobs) {
mDrmDevice->DestroyPropertyBlob(blob);
}
oldBlobs.clear();
}
template<typename StageDataType>
int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorBlob(
const DrmProperty &prop,
const uint32_t type,
const StageDataType &stage,
const typename GsInterfaceType::IDqe &dqe,
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
{
/* dirty bit is valid only if enable is true */
if (!prop.id())
return NO_ERROR;
if (!mForceDisplayColorSetting && stage.enable && !stage.dirty)
return NO_ERROR;
int32_t ret = 0;
uint32_t blobId = 0;
uint64_t lutSize;
if (stage.enable) {
switch (type) {
case DqeBlobs::CGC:
ret = gs::ColorDrmBlobFactory::cgc(dqe.Cgc().config, mDrmDevice, blobId);
break;
case DqeBlobs::DEGAMMA_LUT:
std::tie(ret, lutSize) = mDrmCrtc->degamma_lut_size_property().value();
if (ret < 0) {
HWC_LOGE(mExynosDisplay, "%s: there is no degamma_lut_size (ret = %d)",
__func__, ret);
} else {
ret = gs::ColorDrmBlobFactory::degamma(lutSize, dqe.DegammaLut().config,
mDrmDevice, blobId);
}
break;
case DqeBlobs::REGAMMA_LUT:
std::tie(ret, lutSize) = mDrmCrtc->gamma_lut_size_property().value();
if (ret < 0) {
HWC_LOGE(mExynosDisplay, "%s: there is no gamma_lut_size (ret = %d)", __func__,
ret);
} else {
ret = gs::ColorDrmBlobFactory::regamma(lutSize, dqe.RegammaLut().config,
mDrmDevice, blobId);
}
break;
case DqeBlobs::GAMMA_MAT:
ret = gs::ColorDrmBlobFactory::gammaMatrix(dqe.GammaMatrix().config, mDrmDevice,
blobId);
break;
case DqeBlobs::LINEAR_MAT:
ret = gs::ColorDrmBlobFactory::linearMatrix(dqe.LinearMatrix().config, mDrmDevice,
blobId);
break;
case DqeBlobs::DISP_DITHER:
ret = gs::ColorDrmBlobFactory::displayDither(dqe.DqeControl().config, mDrmDevice,
blobId);
break;
case DqeBlobs::CGC_DITHER:
ret = gs::ColorDrmBlobFactory::cgcDither(dqe.DqeControl().config, mDrmDevice, blobId);
break;
default:
ret = -EINVAL;
}
if (ret != NO_ERROR) {
HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
return ret;
}
}
/* Skip setting when previous and current setting is same with 0 */
if ((blobId == 0) && (mOldDqeBlobs.getBlob(type) == 0))
return ret;
if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
__func__);
return ret;
}
mOldDqeBlobs.addBlob(type, blobId);
// disp_dither and cgc dither are part of DqeCtrl stage and the notification
// will be sent after all data in DqeCtrl stage are applied.
if (type != DqeBlobs::DISP_DITHER && type != DqeBlobs::CGC_DITHER)
stage.NotifyDataApplied();
return ret;
}
int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorSetting(
ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq) {
if (!mForceDisplayColorSetting && !mColorSettingChanged)
return NO_ERROR;
ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mExynosDisplay->mDevice);
gs101::ColorManager* colorManager = device->getDisplayColorManager(mExynosDisplay);
int ret = NO_ERROR;
const typename GsInterfaceType::IDqe& dqe = colorManager->getDqe();
if ((mDrmCrtc->cgc_lut_property().id() != 0) &&
(ret = setDisplayColorBlob(mDrmCrtc->cgc_lut_property(),
static_cast<uint32_t>(DqeBlobs::CGC),
dqe.Cgc(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set Cgc blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->degamma_lut_property(),
static_cast<uint32_t>(DqeBlobs::DEGAMMA_LUT),
dqe.DegammaLut(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set DegammaLut blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_lut_property(),
static_cast<uint32_t>(DqeBlobs::REGAMMA_LUT),
dqe.RegammaLut(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set RegammaLut blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_matrix_property(),
static_cast<uint32_t>(DqeBlobs::GAMMA_MAT),
dqe.GammaMatrix(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set GammaMatrix blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->linear_matrix_property(),
static_cast<uint32_t>(DqeBlobs::LINEAR_MAT),
dqe.LinearMatrix(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set LinearMatrix blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->disp_dither_property(),
static_cast<uint32_t>(DqeBlobs::DISP_DITHER),
dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set DispDither blob fail", __func__);
return ret;
}
if ((ret = setDisplayColorBlob(mDrmCrtc->cgc_dither_property(),
static_cast<uint32_t>(DqeBlobs::CGC_DITHER),
dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: set CgcDither blob fail", __func__);
return ret;
}
const DrmProperty &prop_force_bpc = mDrmCrtc->force_bpc_property();
if (prop_force_bpc.id()) {
uint32_t bpc = static_cast<uint32_t>(BPC_UNSPECIFIED);
if (dqe.DqeControl().enable) {
if (dqe.DqeControl().config->force_10bpc)
bpc = static_cast<uint32_t>(BPC_10);
}
auto [bpcEnum, ret] = DrmEnumParser::halToDrmEnum(bpc, mBpcEnums);
if (ret < 0) {
HWC_LOGE(mExynosDisplay, "Fail to convert bpc(%d)", bpc);
} else {
if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_force_bpc,
bpcEnum, true)) < 0) {
HWC_LOGE(mExynosDisplay, "%s: Fail to set force bpc property",
__func__);
}
}
}
dqe.DqeControl().NotifyDataApplied();
return NO_ERROR;
}
template<typename StageDataType>
int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorBlob(
const std::unique_ptr<DrmPlane> &plane,
const DrmProperty &prop,
const uint32_t type,
const StageDataType &stage,
const typename GsInterfaceType::IDpp &dpp,
const uint32_t dppIndex,
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
bool forceUpdate)
{
/* dirty bit is valid only if enable is true */
if (!prop.id() || (stage.enable && !stage.dirty && !forceUpdate))
return NO_ERROR;
uint32_t ix = 0;
for (;ix < mOldDppBlobs.size(); ix++) {
if (mOldDppBlobs[ix].planeId == plane->id()) {
break;
}
}
if (ix >= mOldDppBlobs.size()) {
HWC_LOGE(mExynosDisplay, "%s: could not find plane %d", __func__, plane->id());
return -EINVAL;
}
DppBlobs &oldDppBlobs = mOldDppBlobs[ix];
int32_t ret = 0;
uint32_t blobId = 0;
if (stage.enable) {
switch (type) {
case DppBlobs::EOTF:
ret = gs::ColorDrmBlobFactory::eotf(dpp.EotfLut().config, mDrmDevice, blobId);
break;
case DppBlobs::GM:
ret = gs::ColorDrmBlobFactory::gm(dpp.Gm().config, mDrmDevice, blobId);
break;
case DppBlobs::DTM:
ret = gs::ColorDrmBlobFactory::dtm(dpp.Dtm().config, mDrmDevice, blobId);
break;
case DppBlobs::OETF:
ret = gs::ColorDrmBlobFactory::oetf(dpp.OetfLut().config, mDrmDevice, blobId);
break;
default:
ret = -EINVAL;
}
if (ret != NO_ERROR) {
HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
return ret;
}
}
/* Skip setting when previous and current setting is same with 0 */
if ((blobId == 0) && (oldDppBlobs.getBlob(type) == 0) && !forceUpdate)
return ret;
if ((ret = drmReq.atomicAddProperty(plane->id(), prop, blobId)) < 0) {
HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
__func__);
return ret;
}
oldDppBlobs.addBlob(type, blobId);
stage.NotifyDataApplied();
return ret;
}
int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorSetting(
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
const std::unique_ptr<DrmPlane> &plane,
const exynos_win_config_data &config, uint32_t &solidColor)
{
if (mColorSettingChanged == false) return NO_ERROR;
if ((config.assignedMPP == nullptr) ||
(config.assignedMPP->mAssignedSources.size() == 0)) {
HWC_LOGE(mExynosDisplay, "%s:: config's mpp source size is invalid",
__func__);
return -EINVAL;
}
ExynosMPPSource* mppSource = config.assignedMPP->mAssignedSources[0];
if (mppSource->mSourceType >= MPP_SOURCE_MAX) {
HWC_LOGE(mExynosDisplay,
"%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
return -EINVAL;
}
ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mExynosDisplay->mDevice);
ColorManager* colorManager = device->getDisplayColorManager(mExynosDisplay);
if (!colorManager) {
HWC_LOGE(mExynosDisplay, "%s: no colorManager for this display", __func__);
return -EINVAL;
}
/*
* Color conversion of Client and Exynos composition buffer
* is already addressed by GLES or G2D. But as of now, 'dim SDR' is only
* supported by HWC/displaycolor, we need put client composition under
* control of HWC/displaycolor.
*/
if (!colorManager->hasDppForLayer(mppSource)) {
if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
HWC_LOGE(mExynosDisplay,
"%s: layer need color conversion but there is no IDpp",
__func__);
return -EINVAL;
} else if (mppSource->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
return NO_ERROR;
} else {
HWC_LOGE(mExynosDisplay,
"%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
return -EINVAL;
}
}
if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
ExynosLayer* layer = (ExynosLayer*)mppSource;
/* color conversion was already handled by m2mMPP */
if ((layer->mM2mMPP != nullptr) &&
(layer->mSrcImg.dataSpace != layer->mMidImg.dataSpace)) {
return NO_ERROR;
}
}
const typename GsInterfaceType::IDpp& dpp = colorManager->getDppForLayer(mppSource);
const uint32_t dppIndex = static_cast<uint32_t>(colorManager->getDppIndexForLayer(mppSource));
bool planeChanged = colorManager->checkAndSaveLayerPlaneId(mppSource, plane->id());
auto &color = dpp.SolidColor();
// exynos_win_config_data.color ARGB
solidColor = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
int ret = 0;
if ((ret = setPlaneColorBlob(plane, plane->eotf_lut_property(),
static_cast<uint32_t>(DppBlobs::EOTF),
dpp.EotfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set oetf blob fail",
__func__, dppIndex);
return ret;
}
if ((ret = setPlaneColorBlob(plane, plane->gammut_matrix_property(),
static_cast<uint32_t>(DppBlobs::GM),
dpp.Gm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set GM blob fail",
__func__, dppIndex);
return ret;
}
if ((ret = setPlaneColorBlob(plane, plane->tone_mapping_property(),
static_cast<uint32_t>(DppBlobs::DTM),
dpp.Dtm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set DTM blob fail",
__func__, dppIndex);
return ret;
}
if ((ret = setPlaneColorBlob(plane, plane->oetf_lut_property(),
static_cast<uint32_t>(DppBlobs::OETF),
dpp.OetfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set OETF blob fail",
__func__, dppIndex);
return ret;
}
return 0;
}
ExynosDisplayDrmInterfaceModule::SaveBlob::~SaveBlob()
{
for (auto &it: blobs) {
mDrmDevice->DestroyPropertyBlob(it);
}
blobs.clear();
}
void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
uint32_t type, uint32_t blob)
{
if (type >= blobs.size()) {
ALOGE("Invalid dqe blop type: %d", type);
return;
}
if (blobs[type] > 0)
mDrmDevice->DestroyPropertyBlob(blobs[type]);
blobs[type] = blob;
}
uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
{
if (type >= blobs.size()) {
ALOGE("Invalid dqe blop type: %d", type);
return 0;
}
return blobs[type];
}
void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
std::vector<displaycolor::DisplayInfo> &display_info) {
displaycolor::DisplayInfo disp_info;
if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) {
disp_info.brightness_ranges = mExynosDisplay->mBrightnessController->getBrightnessRanges();
disp_info.panel_name = GetPanelName();
disp_info.panel_serial = GetPanelSerial();
if (mExynosDisplay->mIndex == 0)
disp_info.display_type = DisplayType::DISPLAY_PRIMARY;
else
disp_info.display_type = DisplayType::DISPLAY_SECONDARY;
} else if (mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL) {
disp_info.display_type = DisplayType::DISPLAY_EXTERNAL;
disp_info.panel_name = "external_display";
disp_info.panel_serial = "0001";
} else {
ALOGE("Unsupported display type (%d) in getDisplayInfo!", mExynosDisplay->mType);
return;
}
display_info.push_back(disp_info);
}
const std::string ExynosDisplayDrmInterfaceModule::GetPanelInfo(const std::string &sysfs_rel,
char delim) {
ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
const std::string& sysfs = display->getPanelSysfsPath();
if (sysfs.empty()) {
return "";
}
std::string info;
if (readLineFromFile(sysfs + "/" + sysfs_rel, info, delim) != OK) {
ALOGE("failed reading %s/%s", sysfs.c_str(), sysfs_rel.c_str());
return "";
}
return info;
}
/* For Histogram */
int32_t ExynosDisplayDrmInterfaceModule::createHistoRoiBlob(uint32_t &blobId) {
struct histogram_roi histo_roi;
std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
histo_roi.start_x = mHistogramInfo->getHistogramROI().start_x;
histo_roi.start_y = mHistogramInfo->getHistogramROI().start_y;
histo_roi.hsize = mHistogramInfo->getHistogramROI().hsize;
histo_roi.vsize = mHistogramInfo->getHistogramROI().vsize;
int ret = mDrmDevice->CreatePropertyBlob(&histo_roi, sizeof(histo_roi), &blobId);
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to create histogram roi blob %d", ret);
return ret;
}
return NO_ERROR;
}
int32_t ExynosDisplayDrmInterfaceModule::createHistoWeightsBlob(uint32_t &blobId) {
struct histogram_weights histo_weights;
std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
histo_weights.weight_r = mHistogramInfo->getHistogramWeights().weight_r;
histo_weights.weight_g = mHistogramInfo->getHistogramWeights().weight_g;
histo_weights.weight_b = mHistogramInfo->getHistogramWeights().weight_b;
int ret = mDrmDevice->CreatePropertyBlob(&histo_weights, sizeof(histo_weights), &blobId);
if (ret) {
HWC_LOGE(mExynosDisplay, "Failed to create histogram weights blob %d", ret);
return ret;
}
return NO_ERROR;
}
int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistoBlob(
const DrmProperty &prop, const uint32_t type,
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
if (!prop.id()) return NO_ERROR;
int32_t ret = NO_ERROR;
uint32_t blobId = 0;
switch (type) {
case HistoBlobs::ROI:
ret = createHistoRoiBlob(blobId);
break;
case HistoBlobs::WEIGHTS:
ret = createHistoWeightsBlob(blobId);
break;
default:
ret = -EINVAL;
}
if (ret != NO_ERROR) {
HWC_LOGE(mExynosDisplay, "%s: Failed to create blob", __func__);
return ret;
}
/* Skip setting when previous and current setting is same with 0 */
if ((blobId == 0) && (mOldHistoBlobs.getBlob(type) == 0)) return ret;
if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
return ret;
}
mOldHistoBlobs.addBlob(type, blobId);
return ret;
}
int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistogramSetting(
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
int ret = NO_ERROR;
if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_roi_property(),
static_cast<uint32_t>(HistoBlobs::ROI), drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_ROI blob", __func__);
return ret;
}
if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_weights_property(),
static_cast<uint32_t>(HistoBlobs::WEIGHTS),
drmReq) != NO_ERROR)) {
HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_Weights blob", __func__);
return ret;
}
const DrmProperty &prop_histo_threshold = mDrmCrtc->histogram_threshold_property();
if (prop_histo_threshold.id()) {
if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_histo_threshold,
(uint64_t)(mHistogramInfo->getHistogramThreshold()),
true)) < 0) {
HWC_LOGE(mExynosDisplay, "%s: Failed to set histogram thereshold property", __func__);
return ret;
}
}
return NO_ERROR;
}
int32_t ExynosDisplayDrmInterfaceModule::setHistogramControl(hidl_histogram_control_t control) {
if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
int ret = NO_ERROR;
uint32_t crtc_id = mDrmCrtc->id();
if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) {
ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_REQUEST, (void *)&crtc_id);
} else if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) {
ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CANCEL, (void *)&crtc_id);
}
return ret;
}
int32_t ExynosDisplayDrmInterfaceModule::setHistogramData(void *bin) {
if (!bin) return -EINVAL;
/*
* There are two handling methods.
* For ContentSampling in HWC_2.3 API, histogram bin needs to be accumulated.
* For Histogram IDL, histogram bin need to be sent to IDL block.
*/
if (mHistogramInfo->getHistogramType() == HistogramInfo::HistogramType::HISTOGRAM_HIDL) {
(mHistogramInfo.get())->callbackHistogram((char16_t *)bin);
} else {
/*
* ContentSampling in HWC2.3 API is not supported
*/
return -ENOTSUP;
}
return NO_ERROR;
}
//////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
: ExynosDisplayDrmInterfaceModule(exynosDisplay)
{
}
ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
{
}
//////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
: ExynosDisplayDrmInterfaceModule(exynosDisplay)
{
}
ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
{
}