You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
7.5 KiB

/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
#include <cutils/trace.h>
#include <drm_logger.h>
#include "drm_atomic_req.h"
#include "drm_connector.h"
#include "drm_crtc.h"
#include "drm_manager.h"
#include "drm_plane.h"
#include "string.h"
#define __CLASS__ "DRMAtomicReq"
namespace sde_drm {
DRMAtomicReq::DRMAtomicReq(int fd, DRMManager *drm_mgr) : drm_mgr_(drm_mgr), fd_(fd) {}
DRMAtomicReq::~DRMAtomicReq() {
if (drm_atomic_req_) {
drmModeAtomicFree(drm_atomic_req_);
drm_atomic_req_ = nullptr;
}
}
int DRMAtomicReq::Init(const DRMDisplayToken &tok) {
token_ = tok;
drm_atomic_req_ = drmModeAtomicAlloc();
if (!drm_atomic_req_) {
return -ENOMEM;
}
return 0;
}
int DRMAtomicReq::Perform(DRMOps opcode, uint32_t obj_id, ...) {
va_list args;
va_start(args, obj_id);
switch (opcode) {
case DRMOps::PLANE_SET_SRC_RECT:
case DRMOps::PLANE_SET_DST_RECT:
case DRMOps::PLANE_SET_ZORDER:
case DRMOps::PLANE_SET_ROTATION:
case DRMOps::PLANE_SET_ALPHA:
case DRMOps::PLANE_SET_BLEND_TYPE:
case DRMOps::PLANE_SET_H_DECIMATION:
case DRMOps::PLANE_SET_V_DECIMATION:
case DRMOps::PLANE_SET_FB_ID:
case DRMOps::PLANE_SET_ROT_FB_ID:
case DRMOps::PLANE_SET_CRTC:
case DRMOps::PLANE_SET_SRC_CONFIG:
case DRMOps::PLANE_SET_INPUT_FENCE:
case DRMOps::PLANE_SET_SCALER_CONFIG:
case DRMOps::PLANE_SET_FB_SECURE_MODE:
case DRMOps::PLANE_SET_CSC_CONFIG:
case DRMOps::PLANE_SET_MULTIRECT_MODE:
case DRMOps::PLANE_SET_EXCL_RECT:
case DRMOps::PLANE_SET_INVERSE_PMA:
case DRMOps::PLANE_SET_DGM_CSC_CONFIG:
case DRMOps::PLANE_SET_POST_PROC:
case DRMOps::PLANE_SET_SSPP_LAYOUT: {
drm_mgr_->GetPlaneMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
} break;
case DRMOps::CRTC_SET_POST_PROC:
case DRMOps::CRTC_SET_MODE:
case DRMOps::CRTC_SET_ACTIVE:
case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET:
case DRMOps::CRTC_SET_CORE_CLK:
case DRMOps::CRTC_SET_CORE_AB:
case DRMOps::CRTC_SET_CORE_IB:
case DRMOps::CRTC_SET_LLCC_AB:
case DRMOps::CRTC_SET_LLCC_IB:
case DRMOps::CRTC_SET_DRAM_AB:
case DRMOps::CRTC_SET_DRAM_IB:
case DRMOps::CRTC_SET_ROT_PREFILL_BW:
case DRMOps::CRTC_SET_ROT_CLK:
case DRMOps::CRTC_GET_RELEASE_FENCE:
case DRMOps::CRTC_SET_ROI:
case DRMOps::CRTC_SET_SECURITY_LEVEL:
case DRMOps::CRTC_SET_SOLIDFILL_STAGES:
case DRMOps::CRTC_SET_IDLE_TIMEOUT:
case DRMOps::CRTC_SET_DEST_SCALER_CONFIG:
case DRMOps::CRTC_SET_CAPTURE_MODE:
case DRMOps::CRTC_SET_IDLE_PC_STATE: {
drm_mgr_->GetCrtcMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
} break;
case DRMOps::CONNECTOR_SET_CRTC:
case DRMOps::CONNECTOR_GET_RETIRE_FENCE:
case DRMOps::CONNECTOR_SET_OUTPUT_RECT:
case DRMOps::CONNECTOR_SET_OUTPUT_FB_ID:
case DRMOps::CONNECTOR_SET_POWER_MODE:
case DRMOps::CONNECTOR_SET_ROI:
case DRMOps::CONNECTOR_SET_AUTOREFRESH:
case DRMOps::CONNECTOR_SET_FB_SECURE_MODE:
case DRMOps::CONNECTOR_SET_POST_PROC:
case DRMOps::CONNECTOR_SET_HDR_METADATA:
case DRMOps::CONNECTOR_SET_QSYNC_MODE:
case DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL:
case DRMOps::CONNECTOR_SET_FRAME_TRIGGER:
case DRMOps::CONNECTOR_SET_COLORSPACE: {
drm_mgr_->GetConnectorMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
} break;
case DRMOps::DPPS_CACHE_FEATURE: {
drm_mgr_->GetDppsMgrIntf()->CacheDppsFeature(obj_id, args);
} break;
case DRMOps::DPPS_COMMIT_FEATURE: {
drm_mgr_->GetDppsMgrIntf()->CommitDppsFeatures(drm_atomic_req_, token_);
} break;
default:
DRM_LOGE("Invalid opcode %d", opcode);
}
va_end(args);
return 0;
}
int DRMAtomicReq::CallAtomic(DRMCrtc *crtc, uint32_t flags)
{
auto plane_mgr = drm_mgr_->GetPlaneMgr();
size_t cnt;
cnt = plane_mgr->ApplyDirtyProperties(drm_atomic_req_);
ATRACE_INT("dirtyPlaneProps", cnt);
cnt = crtc->ApplyDirtyProperties(drm_atomic_req_);
ATRACE_INT("dirtyCrtcProps", cnt);
int ret = drmModeAtomicCommit(fd_, drm_atomic_req_, flags, nullptr);
if (ret) {
DRM_LOGE("drmModeAtomicCommit failed with error %d (%s).", errno, strerror(errno));
/* reset all properties so next atomic commit applies all values */
crtc->ClearProperties();
plane_mgr->ClearProperties();
}
// reset the drm_atomic_req_ for next call
drmModeAtomicSetCursor(drm_atomic_req_, 0);
return ret;
}
int DRMAtomicReq::Validate() {
auto crtc = drm_mgr_->GetCrtcMgr()->GetObject(token_.crtc_id);
if (crtc == nullptr) {
DRM_LOGE("Invalid crtc %d", token_.crtc_id);
return -EINVAL;
}
drm_mgr_->GetPlaneMgr()->UnsetUnusedResources(token_.crtc_id, false /*is_commit*/,
drm_atomic_req_);
int ret = CallAtomic(crtc, DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_TEST_ONLY);
if (!ret)
crtc->PostValidate();
// reset any dirty properties, all properties should be set again before Commit
crtc->DiscardDirtyProperties();
drm_mgr_->GetPlaneMgr()->PostValidate(token_.crtc_id);
return ret;
}
int DRMAtomicReq::Commit(bool synchronous, bool retain_planes) {
DTRACE_SCOPED();
auto crtc = drm_mgr_->GetCrtcMgr()->GetObject(token_.crtc_id);
if (crtc == nullptr) {
DRM_LOGE("Invalid crtc %d", token_.crtc_id);
return -EINVAL;
}
if (retain_planes) {
// It is not enough to simply avoid calling UnsetUnusedPlanes, since state transitons have to
// be correct when CommitPlaneState is called
drm_mgr_->GetPlaneMgr()->RetainPlanes(token_.crtc_id);
}
drm_mgr_->GetPlaneMgr()->UnsetUnusedResources(token_.crtc_id, true /*is_commit*/,
drm_atomic_req_);
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
if (!synchronous) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}
int ret = CallAtomic(crtc, flags);
drm_mgr_->GetPlaneMgr()->PostCommit(token_.crtc_id, !ret);
crtc->PostCommit(!ret);
ATRACE_INT("dirtyPlaneProps", 0);
ATRACE_INT("dirtyCrtcProps", 0);
return ret;
}
} // namespace sde_drm