193 lines
5.4 KiB
C++
193 lines
5.4 KiB
C++
/*
|
|
* Copyright (C) 2022 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_TAG "drmhwc"
|
|
|
|
#include "DrmDisplayPipeline.h"
|
|
|
|
#include "compositor/CompositionPlanner.h"
|
|
#include "drm/DrmAtomicStateManager.h"
|
|
#include "drm/DrmConnector.h"
|
|
#include "drm/DrmCrtc.h"
|
|
#include "drm/DrmDevice.h"
|
|
#include "drm/DrmEncoder.h"
|
|
#include "drm/DrmPlane.h"
|
|
#include "utils/log.h"
|
|
#include "utils/properties.h"
|
|
|
|
namespace android::drm_hwcomposer {
|
|
|
|
static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
|
|
DrmEncoder &enc, DrmCrtc &crtc)
|
|
-> std::unique_ptr<DrmDisplayPipeline> {
|
|
/* Check if resources are available */
|
|
|
|
auto pipe = std::make_unique<DrmDisplayPipeline>();
|
|
pipe->device = &dev;
|
|
|
|
pipe->connector = connector.BindPipeline(pipe.get());
|
|
pipe->encoder = enc.BindPipeline(pipe.get());
|
|
pipe->crtc = crtc.BindPipeline(pipe.get());
|
|
|
|
if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
|
|
return {};
|
|
}
|
|
|
|
std::vector<DrmPlane *> primary_planes;
|
|
|
|
/* Attach necessary resources */
|
|
auto display_planes = std::vector<DrmPlane *>();
|
|
for (const auto &plane : dev.GetPlanes()) {
|
|
if (plane->IsCrtcSupported(crtc)) {
|
|
switch (plane->GetType()) {
|
|
case DRM_PLANE_TYPE_PRIMARY:
|
|
primary_planes.emplace_back(plane.get());
|
|
break;
|
|
case DRM_PLANE_TYPE_OVERLAY:
|
|
case DRM_PLANE_TYPE_CURSOR:
|
|
break;
|
|
default:
|
|
ALOGE("Unknown type for plane %d", plane->GetId());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (primary_planes.empty()) {
|
|
ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
|
|
return {};
|
|
}
|
|
|
|
for (const auto &plane : primary_planes) {
|
|
pipe->primary_plane = plane->BindPipeline(pipe.get());
|
|
if (pipe->primary_plane) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pipe->primary_plane) {
|
|
ALOGE("Failed to bind primary plane");
|
|
return {};
|
|
}
|
|
|
|
pipe->atomic_state_manager = DrmAtomicStateManager::CreateInstance(
|
|
pipe.get());
|
|
|
|
return pipe;
|
|
}
|
|
|
|
static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
|
|
DrmEncoder &enc)
|
|
-> std::unique_ptr<DrmDisplayPipeline> {
|
|
/* First try to use the currently-bound crtc */
|
|
auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
|
|
if (crtc != nullptr) {
|
|
auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
|
|
if (pipeline) {
|
|
return pipeline;
|
|
}
|
|
}
|
|
|
|
/* Try to find a possible crtc which will work */
|
|
for (const auto &crtc : dev.GetCrtcs()) {
|
|
if (enc.SupportsCrtc(*crtc)) {
|
|
auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
|
|
if (pipeline) {
|
|
return pipeline;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We can't use this encoder, but nothing went wrong, try another one */
|
|
return {};
|
|
}
|
|
|
|
auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
|
|
-> std::unique_ptr<DrmDisplayPipeline> {
|
|
auto &dev = connector.GetDev();
|
|
/* Try to use current setup first */
|
|
auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
|
|
|
|
if (encoder != nullptr) {
|
|
auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
|
|
if (pipeline) {
|
|
return pipeline;
|
|
}
|
|
}
|
|
|
|
for (const auto &enc : dev.GetEncoders()) {
|
|
if (connector.SupportsEncoder(*enc)) {
|
|
auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
|
|
if (pipeline) {
|
|
return pipeline;
|
|
}
|
|
}
|
|
}
|
|
|
|
ALOGE("Could not find a suitable encoder/crtc for connector %s",
|
|
connector.GetName().c_str());
|
|
|
|
return {};
|
|
}
|
|
|
|
auto DrmDisplayPipeline::GetUsablePlanes() const -> UsablePlanes {
|
|
UsablePlanes pair;
|
|
auto &[planes, cursor] = pair;
|
|
|
|
planes.emplace_back(primary_plane);
|
|
|
|
for (const auto &plane : device->GetPlanes()) {
|
|
if (plane->IsCrtcSupported(*crtc->Get())) {
|
|
if (Properties::UseOverlayPlanes() &&
|
|
plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
|
|
auto op = plane->BindPipeline(this, true);
|
|
if (op) {
|
|
planes.emplace_back(op);
|
|
}
|
|
} else if (plane->GetType() == DRM_PLANE_TYPE_CURSOR) {
|
|
if (cursor) {
|
|
ALOGW(
|
|
"Encountered multiple cursor planes for CRTC %d. Ignoring "
|
|
"plane %d",
|
|
crtc->Get()->GetId(), plane->GetId());
|
|
} else {
|
|
cursor = plane->BindPipeline(this, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pair;
|
|
}
|
|
|
|
DrmConnector *DrmDisplayPipeline::FindWritebackConnectorForPipeline() const {
|
|
for (const auto &wb_connector : device->GetWritebackConnectors()) {
|
|
for (const auto &encoder : device->GetEncoders()) {
|
|
if (wb_connector->SupportsEncoder(*encoder) &&
|
|
encoder->SupportsCrtc(*(crtc->Get()))) {
|
|
return wb_connector.get();
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
DrmDisplayPipeline::~DrmDisplayPipeline() {
|
|
if (atomic_state_manager)
|
|
atomic_state_manager->StopThread();
|
|
}
|
|
|
|
} // namespace android::drm_hwcomposer
|