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.
420 lines
15 KiB
420 lines
15 KiB
/*
|
|
* Copyright (C) 2017 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 <composer-vts/2.1/ComposerVts.h>
|
|
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace graphics {
|
|
namespace composer {
|
|
namespace V2_1 {
|
|
namespace vts {
|
|
|
|
Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
|
|
// ASSERT_* can only be used in functions returning void.
|
|
[this] {
|
|
ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
|
|
|
|
std::vector<IComposer::Capability> capabilities = getCapabilities();
|
|
mCapabilities.insert(capabilities.begin(), capabilities.end());
|
|
}();
|
|
}
|
|
|
|
sp<IComposer> Composer::getRaw() const {
|
|
return mComposer;
|
|
}
|
|
|
|
bool Composer::hasCapability(IComposer::Capability capability) const {
|
|
return mCapabilities.count(capability) > 0;
|
|
}
|
|
|
|
std::vector<IComposer::Capability> Composer::getCapabilities() {
|
|
std::vector<IComposer::Capability> capabilities;
|
|
mComposer->getCapabilities(
|
|
[&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
|
|
|
|
return capabilities;
|
|
}
|
|
|
|
std::string Composer::dumpDebugInfo() {
|
|
std::string debugInfo;
|
|
mComposer->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
|
|
|
|
return debugInfo;
|
|
}
|
|
|
|
std::unique_ptr<ComposerClient> Composer::createClient() {
|
|
std::unique_ptr<ComposerClient> client;
|
|
mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
|
|
client = std::make_unique<ComposerClient>(tmpClient);
|
|
});
|
|
|
|
return client;
|
|
}
|
|
|
|
ComposerClient::ComposerClient(const sp<IComposerClient>& client) : mClient(client) {}
|
|
|
|
ComposerClient::~ComposerClient() {
|
|
for (const auto& it : mDisplayResources) {
|
|
Display display = it.first;
|
|
const DisplayResource& resource = it.second;
|
|
|
|
for (auto layer : resource.layers) {
|
|
EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer))
|
|
<< "failed to destroy layer " << layer;
|
|
}
|
|
|
|
if (resource.isVirtual) {
|
|
EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display))
|
|
<< "failed to destroy virtual display " << display;
|
|
}
|
|
}
|
|
mDisplayResources.clear();
|
|
}
|
|
|
|
sp<IComposerClient> ComposerClient::getRaw() const {
|
|
return mClient;
|
|
}
|
|
|
|
void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) {
|
|
mClient->registerCallback(callback);
|
|
}
|
|
|
|
uint32_t ComposerClient::getMaxVirtualDisplayCount() {
|
|
return mClient->getMaxVirtualDisplayCount();
|
|
}
|
|
|
|
Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height,
|
|
PixelFormat formatHint, uint32_t outputBufferSlotCount,
|
|
PixelFormat* outFormat) {
|
|
Display display = 0;
|
|
mClient->createVirtualDisplay(
|
|
width, height, formatHint, outputBufferSlotCount,
|
|
[&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
|
|
display = tmpDisplay;
|
|
*outFormat = tmpFormat;
|
|
|
|
ASSERT_TRUE(mDisplayResources.insert({display, DisplayResource(true)}).second)
|
|
<< "duplicated virtual display id " << display;
|
|
});
|
|
|
|
return display;
|
|
}
|
|
|
|
void ComposerClient::destroyVirtualDisplay(Display display) {
|
|
Error error = mClient->destroyVirtualDisplay(display);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to destroy virtual display " << display;
|
|
|
|
mDisplayResources.erase(display);
|
|
}
|
|
|
|
Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) {
|
|
Layer layer = 0;
|
|
mClient->createLayer(display, bufferSlotCount, [&](const auto& tmpError, const auto& tmpLayer) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer";
|
|
layer = tmpLayer;
|
|
|
|
auto resourceIt = mDisplayResources.find(display);
|
|
if (resourceIt == mDisplayResources.end()) {
|
|
resourceIt = mDisplayResources.insert({display, DisplayResource(false)}).first;
|
|
}
|
|
|
|
ASSERT_TRUE(resourceIt->second.layers.insert(layer).second)
|
|
<< "duplicated layer id " << layer;
|
|
});
|
|
|
|
return layer;
|
|
}
|
|
|
|
void ComposerClient::destroyLayer(Display display, Layer layer) {
|
|
Error error = mClient->destroyLayer(display, layer);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer;
|
|
|
|
auto resourceIt = mDisplayResources.find(display);
|
|
ASSERT_NE(mDisplayResources.end(), resourceIt);
|
|
resourceIt->second.layers.erase(layer);
|
|
}
|
|
|
|
Config ComposerClient::getActiveConfig(Display display) {
|
|
Config config = 0;
|
|
mClient->getActiveConfig(display, [&](const auto& tmpError, const auto& tmpConfig) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config";
|
|
config = tmpConfig;
|
|
});
|
|
|
|
return config;
|
|
}
|
|
|
|
bool ComposerClient::getClientTargetSupport(Display display, uint32_t width, uint32_t height,
|
|
PixelFormat format, Dataspace dataspace) {
|
|
Error error = mClient->getClientTargetSupport(display, width, height, format, dataspace);
|
|
return error == Error::NONE;
|
|
}
|
|
|
|
std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
|
|
std::vector<ColorMode> modes;
|
|
mClient->getColorModes(display, [&](const auto& tmpError, const auto& tmpMode) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode";
|
|
modes = tmpMode;
|
|
});
|
|
|
|
return modes;
|
|
}
|
|
|
|
int32_t ComposerClient::getDisplayAttribute(Display display, Config config,
|
|
IComposerClient::Attribute attribute) {
|
|
int32_t value = 0;
|
|
mClient->getDisplayAttribute(
|
|
display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get display attribute";
|
|
value = tmpValue;
|
|
});
|
|
|
|
return value;
|
|
}
|
|
|
|
std::vector<Config> ComposerClient::getDisplayConfigs(Display display) {
|
|
std::vector<Config> configs;
|
|
mClient->getDisplayConfigs(display, [&](const auto& tmpError, const auto& tmpConfigs) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs";
|
|
configs = tmpConfigs;
|
|
});
|
|
|
|
return configs;
|
|
}
|
|
|
|
std::string ComposerClient::getDisplayName(Display display) {
|
|
std::string name;
|
|
mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name";
|
|
name = tmpName.c_str();
|
|
});
|
|
|
|
return name;
|
|
}
|
|
|
|
IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) {
|
|
IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
|
|
mClient->getDisplayType(display, [&](const auto& tmpError, const auto& tmpType) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type";
|
|
type = tmpType;
|
|
});
|
|
|
|
return type;
|
|
}
|
|
|
|
bool ComposerClient::getDozeSupport(Display display) {
|
|
bool support = false;
|
|
mClient->getDozeSupport(display, [&](const auto& tmpError, const auto& tmpSupport) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support";
|
|
support = tmpSupport;
|
|
});
|
|
|
|
return support;
|
|
}
|
|
|
|
std::vector<Hdr> ComposerClient::getHdrCapabilities(Display display, float* outMaxLuminance,
|
|
float* outMaxAverageLuminance,
|
|
float* outMinLuminance) {
|
|
std::vector<Hdr> types;
|
|
mClient->getHdrCapabilities(
|
|
display, [&](const auto& tmpError, const auto& tmpTypes, const auto& tmpMaxLuminance,
|
|
const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) {
|
|
ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
|
|
types = tmpTypes;
|
|
*outMaxLuminance = tmpMaxLuminance;
|
|
*outMaxAverageLuminance = tmpMaxAverageLuminance;
|
|
*outMinLuminance = tmpMinLuminance;
|
|
});
|
|
|
|
return types;
|
|
}
|
|
|
|
void ComposerClient::setClientTargetSlotCount(Display display, uint32_t clientTargetSlotCount) {
|
|
Error error = mClient->setClientTargetSlotCount(display, clientTargetSlotCount);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count";
|
|
}
|
|
|
|
void ComposerClient::setActiveConfig(Display display, Config config) {
|
|
Error error = mClient->setActiveConfig(display, config);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to set active config";
|
|
}
|
|
|
|
void ComposerClient::setColorMode(Display display, ColorMode mode) {
|
|
Error error = mClient->setColorMode(display, mode);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to set color mode";
|
|
}
|
|
|
|
void ComposerClient::setPowerMode(Display display, IComposerClient::PowerMode mode) {
|
|
Error error = mClient->setPowerMode(display, mode);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to set power mode";
|
|
}
|
|
|
|
void ComposerClient::setVsyncEnabled(Display display, bool enabled) {
|
|
IComposerClient::Vsync vsync =
|
|
(enabled) ? IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
|
|
Error error = mClient->setVsyncEnabled(display, vsync);
|
|
ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode";
|
|
|
|
// give the hwbinder thread some time to handle any pending vsync callback
|
|
if (!enabled) {
|
|
usleep(5 * 1000);
|
|
}
|
|
}
|
|
|
|
void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* writer) {
|
|
bool queueChanged = false;
|
|
uint32_t commandLength = 0;
|
|
hidl_vec<hidl_handle> commandHandles;
|
|
ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
|
|
|
|
if (queueChanged) {
|
|
auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
|
|
ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
|
|
}
|
|
|
|
mClient->executeCommands(commandLength, commandHandles,
|
|
[&](const auto& tmpError, const auto& tmpOutQueueChanged,
|
|
const auto& tmpOutLength, const auto& tmpOutHandles) {
|
|
ASSERT_EQ(Error::NONE, tmpError);
|
|
|
|
if (tmpOutQueueChanged) {
|
|
mClient->getOutputCommandQueue(
|
|
[&](const auto& tmpError, const auto& tmpDescriptor) {
|
|
ASSERT_EQ(Error::NONE, tmpError);
|
|
reader->setMQDescriptor(tmpDescriptor);
|
|
});
|
|
}
|
|
|
|
ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
|
|
reader->parse();
|
|
});
|
|
reader->reset();
|
|
writer->reset();
|
|
}
|
|
|
|
NativeHandleWrapper::~NativeHandleWrapper() {
|
|
if (mHandle) {
|
|
mGralloc.freeBuffer(mHandle);
|
|
}
|
|
}
|
|
|
|
Gralloc::Gralloc() {
|
|
[this] {
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
|
|
/*errOnFailure=*/false));
|
|
if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
|
|
mGralloc4 = nullptr;
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
|
|
/*errOnFailure=*/false));
|
|
if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
|
|
mGralloc3 = nullptr;
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
|
|
}
|
|
}
|
|
}();
|
|
}
|
|
|
|
const NativeHandleWrapper Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
|
|
PixelFormat format, uint64_t usage, bool import,
|
|
uint32_t* outStride) {
|
|
const native_handle_t* handle;
|
|
if (mGralloc4) {
|
|
IMapper4::BufferDescriptorInfo info{};
|
|
info.width = width;
|
|
info.height = height;
|
|
info.layerCount = layerCount;
|
|
info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
|
|
info.usage = usage;
|
|
handle = mGralloc4->allocate(info, import, outStride);
|
|
} else if (mGralloc3) {
|
|
IMapper3::BufferDescriptorInfo info{};
|
|
info.width = width;
|
|
info.height = height;
|
|
info.layerCount = layerCount;
|
|
info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
|
|
info.usage = usage;
|
|
handle = mGralloc3->allocate(info, import, outStride);
|
|
} else {
|
|
IMapper2::BufferDescriptorInfo info{};
|
|
info.width = width;
|
|
info.height = height;
|
|
info.layerCount = layerCount;
|
|
info.format = format;
|
|
info.usage = usage;
|
|
handle = mGralloc2->allocate(info, import, outStride);
|
|
}
|
|
return NativeHandleWrapper(*this, handle);
|
|
}
|
|
|
|
void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
|
|
const AccessRegion& accessRegionRect, int acquireFence) {
|
|
if (mGralloc4) {
|
|
IMapper4::Rect accessRegion;
|
|
accessRegion.left = accessRegionRect.left;
|
|
accessRegion.top = accessRegionRect.top;
|
|
accessRegion.width = accessRegionRect.width;
|
|
accessRegion.height = accessRegionRect.height;
|
|
return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
|
|
} else if (mGralloc3) {
|
|
IMapper3::Rect accessRegion;
|
|
accessRegion.left = accessRegionRect.left;
|
|
accessRegion.top = accessRegionRect.top;
|
|
accessRegion.width = accessRegionRect.width;
|
|
accessRegion.height = accessRegionRect.height;
|
|
int32_t bytesPerPixel;
|
|
int32_t bytesPerStride;
|
|
return mGralloc3->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
|
|
&bytesPerStride);
|
|
} else {
|
|
IMapper2::Rect accessRegion;
|
|
accessRegion.left = accessRegionRect.left;
|
|
accessRegion.top = accessRegionRect.top;
|
|
accessRegion.width = accessRegionRect.width;
|
|
accessRegion.height = accessRegionRect.height;
|
|
return mGralloc2->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
|
|
}
|
|
}
|
|
|
|
int Gralloc::unlock(const native_handle_t* bufferHandle) {
|
|
if (mGralloc4) {
|
|
return mGralloc4->unlock(bufferHandle);
|
|
} else if (mGralloc3) {
|
|
return mGralloc3->unlock(bufferHandle);
|
|
} else {
|
|
return mGralloc2->unlock(bufferHandle);
|
|
}
|
|
}
|
|
|
|
void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
|
|
if (mGralloc4) {
|
|
mGralloc4->freeBuffer(bufferHandle);
|
|
} else if (mGralloc3) {
|
|
mGralloc3->freeBuffer(bufferHandle);
|
|
} else {
|
|
mGralloc2->freeBuffer(bufferHandle);
|
|
}
|
|
}
|
|
|
|
} // namespace vts
|
|
} // namespace V2_1
|
|
} // namespace composer
|
|
} // namespace graphics
|
|
} // namespace hardware
|
|
} // namespace android
|