blob: 4fda5ae3a3d81ae1286dbc84fe3d7a8429df180a [file] [log] [blame]
/*
* Copyright 2016 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 "HwcPassthrough"
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <log/log.h>
#include "ComposerClient.h"
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_1 {
namespace implementation {
ComposerClient::ComposerClient(ComposerHal& hal)
: mHal(hal)
{
}
ComposerClient::~ComposerClient()
{
ALOGD("destroying composer client");
mHal.enableCallback(false);
destroyResources();
mHal.removeClient();
ALOGD("removed composer client");
}
void ComposerClient::destroyResources()
{
// We want to call hwc2_close here (and move hwc2_open to the
// constructor), with the assumption that hwc2_close would
//
// - clean up all resources owned by the client
// - make sure all displays are blank (since there is no layer)
//
// But since SF used to crash at this point, different hwcomposer2
// implementations behave differently on hwc2_close. Our only portable
// choice really is to abort(). But that is not an option anymore
// because we might also have VTS or VR as clients that can come and go.
//
// Below we manually clean all resources (layers and virtual
// displays), and perform a presentDisplay afterwards.
mResources->clear([this](Display display, bool isVirtual, const std::vector<Layer> layers) {
ALOGW("destroying client resources for display %" PRIu64, display);
for (auto layer : layers) {
mHal.destroyLayer(display, layer);
}
if (isVirtual) {
mHal.destroyVirtualDisplay(display);
} else {
ALOGW("performing a final presentDisplay");
std::vector<Layer> changedLayers;
std::vector<IComposerClient::Composition> compositionTypes;
uint32_t displayRequestMask = 0;
std::vector<Layer> requestedLayers;
std::vector<uint32_t> requestMasks;
mHal.validateDisplay(display, &changedLayers, &compositionTypes, &displayRequestMask,
&requestedLayers, &requestMasks);
mHal.acceptDisplayChanges(display);
int32_t presentFence = -1;
std::vector<Layer> releasedLayers;
std::vector<int32_t> releaseFences;
mHal.presentDisplay(display, &presentFence, &releasedLayers, &releaseFences);
if (presentFence >= 0) {
close(presentFence);
}
for (auto fence : releaseFences) {
if (fence >= 0) {
close(fence);
}
}
}
});
mResources.reset();
}
void ComposerClient::initialize()
{
mResources = createResources();
if (!mResources) {
LOG_ALWAYS_FATAL("failed to create resources");
}
mCommandEngine = createCommandEngine();
}
void ComposerClient::onHotplug(Display display,
IComposerCallback::Connection connected)
{
if (connected == IComposerCallback::Connection::CONNECTED) {
mResources->addPhysicalDisplay(display);
} else if (connected == IComposerCallback::Connection::DISCONNECTED) {
mResources->removeDisplay(display);
}
auto ret = mCallback->onHotplug(display, connected);
ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s",
ret.description().c_str());
}
void ComposerClient::onRefresh(Display display)
{
auto ret = mCallback->onRefresh(display);
ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s",
ret.description().c_str());
}
void ComposerClient::onVsync(Display display, int64_t timestamp)
{
auto ret = mCallback->onVsync(display, timestamp);
ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s",
ret.description().c_str());
}
Return<void> ComposerClient::registerCallback(
const sp<IComposerCallback>& callback)
{
// no locking as we require this function to be called only once
mCallback = callback;
mHal.enableCallback(callback != nullptr);
return Void();
}
Return<uint32_t> ComposerClient::getMaxVirtualDisplayCount()
{
return mHal.getMaxVirtualDisplayCount();
}
Return<void> ComposerClient::createVirtualDisplay(uint32_t width,
uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
createVirtualDisplay_cb hidl_cb)
{
Display display = 0;
Error err = mHal.createVirtualDisplay(width, height,
&formatHint, &display);
if (err == Error::NONE) {
mResources->addVirtualDisplay(display, outputBufferSlotCount);
}
hidl_cb(err, display, formatHint);
return Void();
}
Return<Error> ComposerClient::destroyVirtualDisplay(Display display)
{
Error err = mHal.destroyVirtualDisplay(display);
if (err == Error::NONE) {
mResources->removeDisplay(display);
}
return err;
}
Return<void> ComposerClient::createLayer(Display display,
uint32_t bufferSlotCount, createLayer_cb hidl_cb)
{
Layer layer = 0;
Error err = mHal.createLayer(display, &layer);
if (err == Error::NONE) {
err = mResources->addLayer(display, layer, bufferSlotCount);
if (err != Error::NONE) {
// The display entry may have already been removed by onHotplug.
// Note: We do not destroy the layer on this error as the hotplug
// disconnect invalidates the display id. The implementation should
// ensure all layers for the display are destroyed.
}
}
hidl_cb(err, layer);
return Void();
}
Return<Error> ComposerClient::destroyLayer(Display display, Layer layer)
{
Error err = mHal.destroyLayer(display, layer);
if (err == Error::NONE) {
mResources->removeLayer(display, layer);
}
return err;
}
Return<void> ComposerClient::getActiveConfig(Display display,
getActiveConfig_cb hidl_cb)
{
Config config = 0;
Error err = mHal.getActiveConfig(display, &config);
hidl_cb(err, config);
return Void();
}
Return<Error> ComposerClient::getClientTargetSupport(Display display,
uint32_t width, uint32_t height,
PixelFormat format, Dataspace dataspace)
{
Error err = mHal.getClientTargetSupport(display,
width, height, format, dataspace);
return err;
}
Return<void> ComposerClient::getColorModes(Display display,
getColorModes_cb hidl_cb)
{
hidl_vec<ColorMode> modes;
Error err = mHal.getColorModes(display, &modes);
hidl_cb(err, modes);
return Void();
}
Return<void> ComposerClient::getDisplayAttribute(Display display,
Config config, Attribute attribute,
getDisplayAttribute_cb hidl_cb)
{
int32_t value = 0;
Error err = mHal.getDisplayAttribute(display, config, attribute, &value);
hidl_cb(err, value);
return Void();
}
Return<void> ComposerClient::getDisplayConfigs(Display display,
getDisplayConfigs_cb hidl_cb)
{
hidl_vec<Config> configs;
Error err = mHal.getDisplayConfigs(display, &configs);
hidl_cb(err, configs);
return Void();
}
Return<void> ComposerClient::getDisplayName(Display display,
getDisplayName_cb hidl_cb)
{
hidl_string name;
Error err = mHal.getDisplayName(display, &name);
hidl_cb(err, name);
return Void();
}
Return<void> ComposerClient::getDisplayType(Display display,
getDisplayType_cb hidl_cb)
{
DisplayType type = DisplayType::INVALID;
Error err = mHal.getDisplayType(display, &type);
hidl_cb(err, type);
return Void();
}
Return<void> ComposerClient::getDozeSupport(Display display,
getDozeSupport_cb hidl_cb)
{
bool support = false;
Error err = mHal.getDozeSupport(display, &support);
hidl_cb(err, support);
return Void();
}
Return<void> ComposerClient::getHdrCapabilities(Display display,
getHdrCapabilities_cb hidl_cb)
{
hidl_vec<Hdr> types;
float max_lumi = 0.0f;
float max_avg_lumi = 0.0f;
float min_lumi = 0.0f;
Error err = mHal.getHdrCapabilities(display, &types,
&max_lumi, &max_avg_lumi, &min_lumi);
hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
return Void();
}
Return<Error> ComposerClient::setClientTargetSlotCount(Display display,
uint32_t clientTargetSlotCount)
{
return mResources->setDisplayClientTargetCacheSize(display, clientTargetSlotCount);
}
Return<Error> ComposerClient::setActiveConfig(Display display, Config config)
{
Error err = mHal.setActiveConfig(display, config);
return err;
}
Return<Error> ComposerClient::setColorMode(Display display, ColorMode mode)
{
Error err = mHal.setColorMode(display, mode);
return err;
}
Return<Error> ComposerClient::setPowerMode(Display display, PowerMode mode)
{
Error err = mHal.setPowerMode(display, mode);
return err;
}
Return<Error> ComposerClient::setVsyncEnabled(Display display, Vsync enabled)
{
Error err = mHal.setVsyncEnabled(display, enabled);
return err;
}
Return<Error> ComposerClient::setInputCommandQueue(
const MQDescriptorSync<uint32_t>& descriptor)
{
std::lock_guard<std::mutex> lock(mCommandEngineMutex);
return mCommandEngine->setInputMQDescriptor(descriptor) ?
Error::NONE : Error::NO_RESOURCES;
}
Return<void> ComposerClient::getOutputCommandQueue(
getOutputCommandQueue_cb hidl_cb)
{
// no locking as we require this function to be called inside
// executeCommands_cb
auto outDescriptor = mCommandEngine->getOutputMQDescriptor();
if (outDescriptor) {
hidl_cb(Error::NONE, *outDescriptor);
} else {
hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
}
return Void();
}
Return<void> ComposerClient::executeCommands(uint32_t inLength,
const hidl_vec<hidl_handle>& inHandles,
executeCommands_cb hidl_cb)
{
std::lock_guard<std::mutex> lock(mCommandEngineMutex);
bool outChanged = false;
uint32_t outLength = 0;
hidl_vec<hidl_handle> outHandles;
Error error = mCommandEngine->execute(inLength, inHandles,
&outChanged, &outLength, &outHandles);
hidl_cb(error, outChanged, outLength, outHandles);
mCommandEngine->reset();
return Void();
}
std::unique_ptr<ComposerResources> ComposerClient::createResources()
{
return ComposerResources::create();
}
std::unique_ptr<ComposerCommandEngine>
ComposerClient::createCommandEngine()
{
return std::make_unique<ComposerCommandEngine>(&mHal, mResources.get());
}
} // namespace implementation
} // namespace V2_1
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android