* Copyright (c) 2024 Huawei Device Co., Ltd.
* 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.
*/
#ifndef OHOS_HDI_DISPLAY_V1_2_DISPLAY_CMD_REQUESTER_H
#define OHOS_HDI_DISPLAY_V1_2_DISPLAY_CMD_REQUESTER_H
#include "v1_1/display_command/display_cmd_requester.h"
#include "v1_2/display_command/display_cmd_utils.h"
#include "v1_2/display_composer_type.h"
#include "v1_2/idisplay_composer.h"
namespace OHOS {
namespace HDI {
namespace Display {
namespace Composer {
namespace V1_2 {
using namespace OHOS::HDI::Base;
template <typename Transfer, typename CompHdi>
class DisplayCmdRequester : public V1_1::DisplayCmdRequester<Transfer, CompHdi> {
public:
DisplayCmdRequester(sptr<CompHdi> hdi) : BaseType1_1(hdi) {}
static std::unique_ptr<DisplayCmdRequester> Create(sptr<CompHdi> hdi)
{
DISPLAY_CHK_RETURN(hdi == nullptr, nullptr, HDF_LOGE("%{public}s: hdi is nullptr", __func__));
auto requester = std::make_unique<DisplayCmdRequester>(hdi);
DISPLAY_CHK_RETURN(requester == nullptr, nullptr,
HDF_LOGE("%{public}s: CmdRequester is nullptr", __func__));
auto ret = requester->Init(CmdUtils::INIT_ELEMENT_COUNT);
if (ret != HDF_SUCCESS) {
HDF_LOGE("DisplayCmdRequester init failed");
return nullptr;
}
return requester;
}
int32_t CommitAndGetReleaseFence(uint32_t devId, int32_t& fence, bool isSupportSkipValidate, int32_t& skipState,
bool& needFlush, std::vector<uint32_t>& layers, std::vector<int32_t>& fences, bool isValidated)
{
uint32_t replyEleCnt = 0;
std::vector<HdifdInfo> outFds;
size_t writePos = requestPacker_.ValidSize();
int32_t ret = CmdUtils::StartSection(REQUEST_CMD_COMMIT_AND_GET_RELEASE_FENCE, requestPacker_);
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = requestPacker_.WriteUint32(devId) ? HDF_SUCCESS : HDF_FAILURE;
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = requestPacker_.WriteBool(isSupportSkipValidate) ? HDF_SUCCESS : HDF_FAILURE;
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = requestPacker_.WriteBool(isValidated) ? HDF_SUCCESS : HDF_FAILURE;
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = CmdUtils::EndSection(requestPacker_);
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ReqStatistic(devId, REQUEST_CMD_COMMIT_AND_GET_RELEASE_FENCE, writePos);
ret = CmdUtils::EndPack(requestPacker_);
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = DoRequest(replyEleCnt, outFds);
DISPLAY_CHECK(ret != HDF_SUCCESS, goto EXIT);
ret = DoReplyResults(replyEleCnt, outFds, [&](void *data) -> int32_t {
FenceData *fenceData = reinterpret_cast<struct FenceData *>(data);
if (fenceData == nullptr) {
fence = -1;
skipState = -1;
needFlush = false;
layers.clear();
fences.clear();
return HDF_FAILURE;
}
fence = fenceData->fence_;
skipState = fenceData->skipValidateState_;
needFlush = fenceData->needFlush_;
layers = fenceData->layers;
fences = fenceData->fences;
return HDF_SUCCESS;
});
if (ret != HDF_SUCCESS) {
HDF_LOGE("DoReplyResults failure, ret=%{public}d", ret);
}
EXIT:
return PeriodDataReset() == HDF_SUCCESS ? ret : HDF_FAILURE;
}
int32_t OnReplySkipStateFailed(CommandDataUnpacker& replyUnpacker, bool &needFlush)
{
uint32_t devId = 0;
bool retBool = replyUnpacker.ReadUint32(devId);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE, HDF_LOGE("%{public}s: read devId failed", __func__));
retBool = replyUnpacker.ReadBool(needFlush);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE, HDF_LOGE("%{public}s: read needFlush failed", __func__));
uint32_t vectSize = 0;
retBool = replyUnpacker.ReadUint32(vectSize);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read vect size failed", __func__));
if (vectSize > CmdUtils::MAX_MEMORY) {
HDF_LOGE("%{public}s: layers vectSize:%{public}u is too large", __func__, vectSize);
return HDF_FAILURE;
}
compChangeLayers_[devId].resize(vectSize);
for (uint32_t i = 0; i < vectSize; i++) {
DISPLAY_CHK_RETURN(replyUnpacker.ReadUint32(compChangeLayers_[devId][i]) == false, HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read layer vector failed", __func__));
}
vectSize = 0;
retBool = replyUnpacker.ReadUint32(vectSize);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read vect size failed", __func__));
if (vectSize > CmdUtils::MAX_MEMORY) {
HDF_LOGE("%{public}s: layers vectSize:%{public}u is too large", __func__, vectSize);
return HDF_FAILURE;
}
compChangeTypes_[devId].resize(vectSize);
for (uint32_t i = 0; i < vectSize; i++) {
DISPLAY_CHK_RETURN(replyUnpacker.ReadInt32(compChangeTypes_[devId][i]) == false, HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read composition type vector failed", __func__));
}
return HDF_SUCCESS;
}
int32_t OnReplyCommitAndGetReleaseFence(CommandDataUnpacker& replyUnpacker,
std::vector<HdifdInfo>& replyFds, int32_t& fenceFd, int32_t& skipState,
bool& needFlush, std::vector<uint32_t>& layers, std::vector<int32_t>& fences)
{
int32_t ret = CmdUtils::FileDescriptorUnpack(replyUnpacker, replyFds, fenceFd);
DISPLAY_CHK_RETURN(ret != HDF_SUCCESS, ret,
HDF_LOGE("%{public}s: FileDescriptorUnpack failed", __func__));
bool retBool = replyUnpacker.ReadInt32(skipState);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: read skipValidateState failed", __func__));
if (skipState != HDF_SUCCESS) {
return OnReplySkipStateFailed(replyUnpacker, needFlush);
} else {
uint32_t vectSize = 0;
DISPLAY_CHK_RETURN(true != replyUnpacker.ReadUint32(vectSize), HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read vect size failed", __func__));
if (vectSize > CmdUtils::MAX_MEMORY) {
HDF_LOGE("%{public}s: layers vectSize:%{public}u is too large", __func__, vectSize);
return HDF_FAILURE;
}
layers.resize(vectSize);
for (uint32_t i = 0; i < vectSize; i++) {
DISPLAY_CHK_RETURN(replyUnpacker.ReadUint32(layers[i]) == false, HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read layer vector failed", __func__));
}
vectSize = 0;
DISPLAY_CHK_RETURN(true != replyUnpacker.ReadUint32(vectSize), HDF_FAILURE,
HDF_LOGE("%{public}s: HDI 1.2 read vect size failed", __func__));
if (vectSize > CmdUtils::MAX_MEMORY) {
HDF_LOGE("%{public}s: layers vectSize:%{public}u is too large", __func__, vectSize);
return HDF_FAILURE;
}
fences.resize(vectSize);
for (uint32_t i = 0; i < vectSize; i++) {
ret = CmdUtils::FileDescriptorUnpack(replyUnpacker, replyFds, fences[i]);
DISPLAY_CHK_RETURN(ret != HDF_SUCCESS, ret,
HDF_LOGE("%{public}s: HDI 1.2 FileDescriptorUnpack failed", __func__));
}
}
return HDF_SUCCESS;
}
int32_t ProcessUnpackCmd(CommandDataUnpacker& replyUnpacker, int32_t unpackCmd,
std::vector<HdifdInfo>& replyFds, std::function<int32_t(void *)> fn)
{
int32_t ret = HDF_SUCCESS;
while (replyUnpacker.NextSection()) {
bool retBool = replyUnpacker.BeginSection(unpackCmd);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: BeginSection failed", __func__));
FenceData fenceData;
std::unordered_map<int32_t, int32_t> errMaps;
switch (unpackCmd) {
case REPLY_CMD_COMMIT_AND_GET_RELEASE_FENCE:
ret = OnReplyCommitAndGetReleaseFence(replyUnpacker, replyFds, fenceData.fence_,
fenceData.skipValidateState_, fenceData.needFlush_, fenceData.layers, fenceData.fences);
DISPLAY_CHK_RETURN(ret != HDF_SUCCESS, ret,
HDF_LOGE("%{public}s: OnReplyCommit failed unpackCmd=%{public}s",
__func__, CmdUtils::CommandToString(unpackCmd)));
ret = fn(&fenceData);
DISPLAY_CHK_RETURN(ret != HDF_SUCCESS, ret,
HDF_LOGE("%{public}s: return fence fd error, unpackCmd=%{public}s",
__func__, CmdUtils::CommandToString(unpackCmd)));
break;
default:
ret = V1_0::DisplayCmdRequester<Transfer, CompHdi>::ProcessUnpackCmd(replyUnpacker,
unpackCmd, replyFds, fn);
DISPLAY_CHK_RETURN(ret != HDF_SUCCESS, ret,
HDF_LOGE("%{public}s: return error, unpackCmd=%{public}s",
__func__, CmdUtils::CommandToString(unpackCmd)));
}
}
return HDF_SUCCESS;
}
int32_t DoReplyResults(uint32_t replyEleCnt, std::vector<HdifdInfo>& replyFds, std::function<int32_t(void *)> fn)
{
CommandDataUnpacker replyUnpacker;
replyUnpacker.Init(replyData_.get(), replyEleCnt << CmdUtils::MOVE_SIZE);
#ifdef DEBUG_DISPLAY_CMD_RAW_DATA
replyUnpacker.Dump();
#endif
int32_t unpackCmd = -1;
bool retBool = replyUnpacker.PackBegin(unpackCmd);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: PackBegin failed", __func__));
if (unpackCmd != CONTROL_CMD_REPLY_BEGIN) {
HDF_LOGE("%{public}s: PackBegin cmd not match, unpackCmd=%{public}d", __func__, unpackCmd);
request_->Reset();
reply_->Reset();
return HDF_FAILURE;
}
if (ProcessUnpackCmd(replyUnpacker, unpackCmd, replyFds, fn) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: ProcessUnpackCmd failed, unpackCmd=%{public}d", __func__, unpackCmd);
request_->Reset();
reply_->Reset();
return HDF_FAILURE;
}
retBool = replyUnpacker.PackEnd(unpackCmd);
DISPLAY_CHK_RETURN(retBool == false, HDF_FAILURE,
HDF_LOGE("%{public}s: PackEnd failed", __func__));
DISPLAY_CHK_RETURN(unpackCmd != CONTROL_CMD_REPLY_END, HDF_FAILURE,
HDF_LOGE("%{public}s: PackEnd failed, endCmd = %{public}s",
__func__, CmdUtils::CommandToString(unpackCmd)));
return HDF_SUCCESS;
}
int32_t SetDisplayConstraint(uint32_t devId, uint64_t frameID, uint64_t ns, uint32_t type)
{
int32_t ret = 0;
bool retBool = false;
size_t writePos = requestPacker_.ValidSize();
do {
ret = CmdUtils::StartSection(REQUEST_CMD_SET_DISPLAY_CONSTRAINT, requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: StartSection failed", __func__));
retBool = requestPacker_.WriteUint32(devId);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write devId failed", __func__));
retBool = requestPacker_.WriteUint64(frameID);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write frameID failed", __func__));
retBool = requestPacker_.WriteUint64(ns);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write ns failed", __func__));
retBool = requestPacker_.WriteUint32(type);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write type failed", __func__));
ret = CmdUtils::EndSection(requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: EndSection failed", __func__));
} while (0);
if (retBool == false || ret != HDF_SUCCESS) {
requestPacker_.RollBack(writePos);
HDF_LOGE("%{public}s: writePos_ rollback", __func__);
return HDF_FAILURE;
}
ReqStatistic(devId, REQUEST_CMD_SET_DISPLAY_CONSTRAINT, writePos);
return HDF_SUCCESS;
}
int32_t SetLayerPerFrameParameterSmq(uint32_t devId, uint32_t layerId, const std::string& key,
const std::vector<int8_t>& value)
{
int32_t ret = 0;
bool retBool = false;
size_t writePos = requestPacker_.ValidSize();
do {
ret = CmdUtils::StartSection(REQUEST_CMD_SET_LAYER_PERFRAME_PARAM, requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: StartSection failed", __func__));
retBool = requestPacker_.WriteUint32(devId);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write devId failed", __func__));
retBool = requestPacker_.WriteUint32(layerId);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write layerId failed", __func__));
uint32_t vectStrSize = key.size();
retBool = requestPacker_.WriteUint32(vectStrSize);
if (vectStrSize > CmdUtils::MAX_MEMORY) {
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vectStr failed", __func__));
}
for (uint32_t i = 0; i < vectStrSize; i++) {
retBool = requestPacker_.WriteInt32(static_cast<int32_t>(key[i]));
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vectStr failed", __func__));
}
uint32_t vectSize = value.size();
retBool = requestPacker_.WriteUint32(vectSize);
if (vectSize > CmdUtils::MAX_MEMORY) {
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vect failed", __func__));
}
for (uint32_t i = 0; i < vectSize; i++) {
retBool = requestPacker_.WriteUint8(static_cast<uint8_t>(value[i]));
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vect failed", __func__));
}
ret = CmdUtils::EndSection(requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: EndSection failed", __func__));
} while (0);
if (retBool == false || ret != HDF_SUCCESS) {
requestPacker_.RollBack(writePos);
HDF_LOGE("SetLayerPerFrameParameterSmq writePos_ rollback %{public}s, %{public}d, %{public}d",
key.c_str(), devId, layerId);
return HDF_FAILURE;
}
ReqStatistic(devId, REQUEST_CMD_SET_DISPLAY_PERFRAME_PARAM, writePos);
return HDF_SUCCESS;
}
int32_t SetDisplayPerFrameParameterSmq(uint32_t devId, const std::string& key,
const std::vector<int8_t>& value)
{
int32_t ret = 0;
bool retBool = false;
size_t writePos = requestPacker_.ValidSize();
do {
ret = CmdUtils::StartSection(REQUEST_CMD_SET_DISPLAY_PERFRAME_PARAM, requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: StartSection failed", __func__));
retBool = requestPacker_.WriteUint32(devId);
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write devId failed", __func__));
uint32_t vectStrSize = key.size();
retBool = requestPacker_.WriteUint32(vectStrSize);
if (vectStrSize > CmdUtils::MAX_MEMORY) {
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vectStr failed", __func__));
}
for (uint32_t i = 0; i < vectStrSize; i++) {
retBool = requestPacker_.WriteInt32(static_cast<int32_t>(key[i]));
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vectStr failed", __func__));
}
uint32_t vectSize = value.size();
retBool = requestPacker_.WriteUint32(vectSize);
if (vectSize > CmdUtils::MAX_MEMORY) {
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vect failed", __func__));
}
for (uint32_t i = 0; i < vectSize; i++) {
retBool = requestPacker_.WriteUint8(static_cast<uint8_t>(value[i]));
DISPLAY_CHK_BREAK(retBool == false,
HDF_LOGE("%{public}s: write vect failed", __func__));
}
ret = CmdUtils::EndSection(requestPacker_);
DISPLAY_CHK_BREAK(ret != HDF_SUCCESS,
HDF_LOGE("%{public}s: EndSection failed", __func__));
} while (0);
if (retBool == false || ret != HDF_SUCCESS) {
requestPacker_.RollBack(writePos);
HDF_LOGE("SetDisplayPerFrameParameterSmq writePos_ rollback %{public}s, %{public}d",
key.c_str(), devId);
return HDF_FAILURE;
}
ReqStatistic(devId, REQUEST_CMD_SET_DISPLAY_PERFRAME_PARAM, writePos);
return HDF_SUCCESS;
}
protected:
using BaseType1_1 = V1_1::DisplayCmdRequester<Transfer, CompHdi>;
using BaseType1_1::request_;
using BaseType1_1::reply_;
using BaseType1_1::requestPacker_;
using BaseType1_1::replyData_;
using BaseType1_1::DoRequest;
using BaseType1_1::PeriodDataReset;
using BaseType1_1::ReqStatistic;
using BaseType1_1::compChangeLayers_;
using BaseType1_1::compChangeTypes_;
struct FenceData {
int32_t fence_ = -1;
int32_t skipValidateState_ = -1;
bool needFlush_ = false;
std::vector<uint32_t> layers;
std::vector<int32_t> fences;
};
};
using HdiDisplayCmdRequester = V1_2::DisplayCmdRequester<SharedMemQueue<int32_t>, V1_2::IDisplayComposer>;
}
}
}
}
}
#endif