| /* |
| * Copyright Samsung Electronics Co.,LTD. |
| * Copyright (C) 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. |
| */ |
| |
| #include <algorithm> |
| |
| #include <log/log.h> |
| |
| #include <hardware/exynos/acryl.h> |
| |
| #include "acrylic_internal.h" |
| |
| Acrylic::Acrylic(const HW2DCapability &capability) |
| : mCapability(capability), mHasBackgroundColor(false), |
| mMaxTargetLuminance(100), mMinTargetLuminance(0), mTargetDisplayInfo(nullptr), |
| mCanvas(this, AcrylicCanvas::CANVAS_TARGET) |
| { |
| ALOGD_TEST("Created a new Acrylic on %p", this); |
| } |
| |
| Acrylic::~Acrylic() |
| { |
| mCanvas.disconnectLayer(); |
| |
| for (auto layer: mLayers) { |
| layer->disconnectLayer(); |
| removeTransitData(layer); |
| } |
| |
| ALOGD_TEST("Destroyed Acrylic on %p", this); |
| } |
| |
| AcrylicLayer *Acrylic::createLayer() |
| { |
| if (mLayers.size() >= getCapabilities().maxLayerCount()) { |
| ALOGE("Full of composit layer: current %zu, max %u", |
| mLayers.size() , getCapabilities().maxLayerCount()); |
| return NULL; |
| } |
| |
| auto *layer = new AcrylicLayer(this); |
| if (!layer) { |
| ALOGE("Failed to create a new compositing layer"); |
| return NULL; |
| } |
| |
| mLayers.push_back(layer); |
| |
| ALOGD_TEST("A new Acrylic layer is created. Total %zd layers", mLayers.size()); |
| |
| return layer; |
| } |
| |
| void Acrylic::removeLayer(AcrylicLayer *layer) |
| { |
| auto it = find(std::begin(mLayers), std::end(mLayers), layer); |
| |
| if (it == std::end(mLayers)) { |
| ALOGE("Deleting an unregistered layer"); |
| } else { |
| removeTransitData(*it); |
| mLayers.erase(it); |
| } |
| } |
| |
| int Acrylic::prioritize(int priority) |
| { |
| if ((priority < -1) || (priority > 15)) { |
| ALOGE("Invalid priority %d", priority); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| bool Acrylic::requestPerformanceQoS(AcrylicPerformanceRequest __unused *request) |
| { |
| return true; |
| } |
| |
| bool Acrylic::setHDRToneMapCoefficients(uint32_t __unused *matrix[2], int __unused num_elements) |
| { |
| return true; |
| } |
| |
| bool Acrylic::validateAllLayers() |
| { |
| const HW2DCapability &cap = getCapabilities(); |
| |
| if (!mCanvas.isSettingOkay()) { |
| ALOGE("Incomplete settting (flags: %#x) on the target layer", |
| mCanvas.getSettingFlags()); |
| return false; |
| } |
| |
| if (mCanvas.isCompressed() && !cap.isFeatureSupported(HW2DCapability::FEATURE_AFBC_ENCODE)) { |
| ALOGE("AFBC encoding is not supported"); |
| return false; |
| } |
| |
| if (mCanvas.isUOrder() && !cap.isFeatureSupported(HW2DCapability::FEATURE_UORDER_WRITE)) { |
| ALOGE("Writing in U-Order is not supported"); |
| return false; |
| } |
| |
| bool prot = false; |
| hw2d_rect_t rect; |
| hw2d_coord_t xy = mCanvas.getImageDimension(); |
| |
| for (auto layer: mLayers) { |
| if (!layer->isSettingOkay()) { |
| ALOGE("Incomplete settting (flags: %#x) on a layer of %zu layers", |
| layer->getSettingFlags(), mLayers.size()); |
| return false; |
| } |
| |
| if (layer->isCompressed() && !cap.isFeatureSupported(HW2DCapability::FEATURE_AFBC_DECODE)) { |
| ALOGE("AFBC decoding is not supported"); |
| return false; |
| } |
| |
| if (layer->isUOrder() && !cap.isFeatureSupported(HW2DCapability::FEATURE_UORDER_READ)) { |
| ALOGE("Reading a texture in U-Order is not supported"); |
| return false; |
| } |
| |
| if ((layer->getPlaneAlpha() != 255) && !cap.isFeatureSupported(HW2DCapability::FEATURE_PLANE_ALPHA)) { |
| ALOGE("Plane alpha is not supported but given %u for plane alpha", layer->getPlaneAlpha()); |
| return false; |
| } |
| |
| rect = layer->getTargetRect(); |
| if (area_is_zero(rect)) { |
| // If no target area is specified to a source layer, |
| // the entire region of the target image becomes the target area. |
| // Then, check the scaling capability |
| hw2d_rect_t ir = layer->getImageRect(); |
| if (!!(layer->getCompositAttr() & AcrylicLayer::ATTR_NORESAMPLING)) { |
| if (!cap.supportedResizing(ir.size, xy, layer->getTransform())) { |
| ALOGE("Unsupported resizing from %dx%d@(%d,%d) --> Target %dx%d with transform %d", |
| ir.size.hori, ir.size.vert, ir.pos.hori, ir.pos.vert, |
| xy.hori, xy.vert, layer->getTransform()); |
| return false; |
| } |
| } else { |
| if (!cap.supportedResampling(ir.size, xy, layer->getTransform())) { |
| ALOGE("Unsupported scaling from %dx%d@(%d,%d) --> Target %dx%d with transform %d", |
| ir.size.hori, ir.size.vert, ir.pos.hori, ir.pos.vert, |
| xy.hori, xy.vert, layer->getTransform()); |
| return false; |
| } |
| } |
| } else if (rect > xy) { |
| ALOGE("Target area %dx%d@(%d,%d) of a layer of %zu layers is out of bound (%dx%d)", |
| rect.size.hori, rect.size.vert, rect.pos.hori, rect.pos.vert, |
| mLayers.size(), xy.hori, xy.vert); |
| return false; |
| } |
| |
| prot = prot || layer->isProtected(); |
| } |
| |
| if (prot && !mCanvas.isProtected()) { |
| ALOGE("Target image is not protected while a source layer is protected"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void Acrylic::sortLayers() |
| { |
| std::sort(std::begin(mLayers), std::end(mLayers), [] (auto l1, auto l2) { return l1->getZOrder() < l2->getZOrder(); }); |
| } |