[Graphics] Add setLayerColorTransform.

This patch adds HAL API to set per-layer color transformation with a 4x4
matrix. Given a 4x4 matrix, the matrix will be applied on the current layer
before composition.

BUG: 111562338
Test: Build, flash and boot, run VtsHalGraphicsComposerV2_3TargetTest
Change-Id: I673cfc2745d35947107dcab19f383ba5a8067605
This commit is contained in:
Peiyong Lin
2018-09-13 17:19:38 -07:00
parent 82ef387215
commit 830137fc08
12 changed files with 317 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ hidl_interface {
],
interfaces: [
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hidl.base@1.0",

View File

@@ -16,12 +16,58 @@
package android.hardware.graphics.composer@2.3;
import android.hardware.graphics.composer@2.1::IComposerClient.Command;
import @2.2::IComposerClient;
import @2.1::Display;
import @2.1::Error;
interface IComposerClient extends @2.2::IComposerClient {
enum Command : @2.2::IComposerClient.Command {
/**
* SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
*
* setLayerColorTransform(float[16] matrix);
*
* This command has the following binary layout in bytes:
*
* 0 - 16 * 4: matrix
*
* Sets a matrix for color transform which will be applied on this layer
* before composition.
*
* If the device is not capable of apply the matrix on this layer, it must force
* this layer to client composition during VALIDATE_DISPLAY.
*
* The matrix provided is an affine color transformation of the following
* form:
*
* |r.r r.g r.b 0|
* |g.r g.g g.b 0|
* |b.r b.g b.b 0|
* |Tr Tg Tb 1|
*
* This matrix must be provided in row-major form:
*
* {r.r, r.g, r.b, 0, g.r, ...}.
*
* Given a matrix of this form and an input color [R_in, G_in, B_in],
* the input color must first be converted to linear space
* [R_linear, G_linear, B_linear], then the output linear color
* [R_out_linear, G_out_linear, B_out_linear] will be:
*
* R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
* G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
* B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
*
* [R_out_linear, G_out_linear, B_out_linear] must then be converted to
* gamma space: [R_out, G_out, B_out] before blending.
*
* @param matrix is a 4x4 transform matrix (16 floats) as described above.
*/
SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT,
};
/**
* Returns the port and data that describe a physical display. The port is
* a unique number that identifies a physical connector (e.g. eDP, HDMI)
@@ -42,4 +88,29 @@ interface IComposerClient extends @2.2::IComposerClient {
uint8_t port,
vec<uint8_t> data);
/**
* Executes commands from the input command message queue. Return values
* generated by the input commands are written to the output command
* message queue in the form of value commands.
*
* @param inLength is the length of input commands.
* @param inHandles is an array of handles referenced by the input
* commands.
* @return error is NONE upon success. Otherwise,
* BAD_PARAMETER when inLength is not equal to the length of
* commands in the input command message queue.
* NO_RESOURCES when the output command message queue was not
* properly drained.
* @param outQueueChanged indicates whether the output command message
* queue has changed.
* @param outLength is the length of output commands.
* @param outHandles is an array of handles referenced by the output
* commands.
*/
executeCommands_2_3(uint32_t inLength,
vec<handle> inHandles)
generates (Error error,
bool outQueueChanged,
uint32_t outLength,
vec<handle> outHandles);
};

View File

@@ -0,0 +1,15 @@
cc_library_headers {
name: "android.hardware.graphics.composer@2.3-command-buffer",
defaults: ["hidl_defaults"],
vendor_available: true,
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
export_include_dirs: ["include"],
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2018 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.
*/
#pragma once
#ifndef LOG_TAG
#warn "ComposerCommandBuffer.h included without LOG_TAG"
#endif
#undef LOG_NDEBUG
#define LOG_NDEBUG 0
#include <android/hardware/graphics/composer/2.3/IComposer.h>
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_3 {
using android::hardware::MessageQueue;
using android::hardware::graphics::composer::V2_1::Error;
using android::hardware::graphics::composer::V2_1::IComposerCallback;
using android::hardware::graphics::composer::V2_1::Layer;
using android::hardware::graphics::composer::V2_3::IComposerClient;
// This class helps build a command queue. Note that all sizes/lengths are in
// units of uint32_t's.
class CommandWriterBase : public V2_2::CommandWriterBase {
public:
CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {}
static constexpr uint16_t kSetLayerColorTransformLength = 16;
void setLayerColorTransform(const float* matrix) {
beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
kSetLayerColorTransformLength);
for (int i = 0; i < 16; i++) {
writeFloat(matrix[i]);
}
endCommand();
}
protected:
void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
V2_2::CommandWriterBase::beginCommand_2_2(
static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
}
};
// This class helps parse a command queue. Note that all sizes/lengths are in
// units of uint32_t's.
class CommandReaderBase : public V2_2::CommandReaderBase {
public:
CommandReaderBase() : V2_2::CommandReaderBase(){};
};
} // namespace V2_3
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -26,9 +26,11 @@ cc_library_headers {
],
header_libs: [
"android.hardware.graphics.composer@2.2-hal",
"android.hardware.graphics.composer@2.3-command-buffer",
],
export_header_lib_headers: [
"android.hardware.graphics.composer@2.2-hal",
"android.hardware.graphics.composer@2.3-command-buffer",
],
export_include_dirs: ["include"],
}

View File

@@ -22,6 +22,7 @@
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
#include <composer-hal/2.3/ComposerClient.h>
#include <composer-hal/2.3/ComposerCommandEngine.h>
#include <composer-hal/2.3/ComposerHal.h>
namespace android {
@@ -55,10 +56,27 @@ class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interfac
return Void();
}
Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
IComposerClient::executeCommands_2_2_cb hidl_cb) override {
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();
}
private:
using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1::mCommandEngine;
using BaseType2_1::mCommandEngineMutex;
using BaseType2_1::mHal;
};

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2018 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.
*/
#pragma once
#ifndef LOG_TAG
#warning "ComposerCommandEngine.h included without LOG_TAG"
#endif
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerResources.h>
#include <composer-hal/2.3/ComposerHal.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_3 {
namespace hal {
class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine {
public:
ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
: BaseType2_2(hal, resources), mHal(hal) {}
protected:
bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
switch (static_cast<IComposerClient::Command>(command)) {
case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM:
return executeSetLayerColorTransform(length);
default:
return BaseType2_2::executeCommand(command, length);
}
}
bool executeSetLayerColorTransform(uint16_t length) {
if (length != CommandWriterBase::kSetLayerColorTransformLength) {
return false;
}
float matrix[16];
for (int i = 0; i < 16; i++) {
matrix[i] = readFloat();
}
auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
if (err != Error::NONE) {
mWriter.setError(getCommandLoc(), err);
}
return true;
}
private:
using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
using BaseType2_1::mWriter;
using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
ComposerHal* mHal;
};
} // namespace hal
} // namespace V2_3
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -27,11 +27,13 @@ namespace hal {
using V2_1::Display;
using V2_1::Error;
using V2_1::Layer;
class ComposerHal : public V2_2::hal::ComposerHal {
public:
virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) = 0;
virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
};
} // namespace hal

View File

@@ -66,6 +66,14 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
return Error::NONE;
}
Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override {
if (!mDispatch.setLayerColorTransform) {
return Error::UNSUPPORTED;
}
int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix);
return static_cast<Error>(err);
}
protected:
bool initDispatch() override {
if (!BaseType2_2::initDispatch()) {
@@ -74,12 +82,15 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
&mDispatch.getDisplayIdentificationData);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
&mDispatch.setLayerColorTransform);
return true;
}
private:
struct {
HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
} mDispatch = {};
using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;

View File

@@ -31,6 +31,7 @@ cc_library_static {
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
],
cflags: [
"-O0",

View File

@@ -40,5 +40,6 @@ cc_test {
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
],
}

View File

@@ -20,7 +20,9 @@
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.3/ComposerVts.h>
namespace android {
@@ -65,6 +67,9 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
// explicitly disable vsync
mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
mComposerCallback->setVsyncAllowed(false);
mWriter = std::make_unique<CommandWriterBase>(1024);
mReader = std::make_unique<V2_1::vts::TestCommandReader>();
}
void TearDown() override {
@@ -75,11 +80,18 @@ class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
}
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
// use the slot count usually set by SF
static constexpr uint32_t kBufferSlotCount = 64;
std::unique_ptr<Composer> mComposer;
std::unique_ptr<ComposerClient> mComposerClient;
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
// the first display and is assumed never to be removed
Display mPrimaryDisplay;
std::unique_ptr<CommandWriterBase> mWriter;
std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
private:
Display waitForFirstDisplay() {
@@ -115,6 +127,31 @@ TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
}
}
/**
* Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
* TODO Add color to the layer, use matrix to keep only red component,
* and check.
*/
TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
Layer layer;
ASSERT_NO_FATAL_FAILURE(layer =
mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
mWriter->selectDisplay(mPrimaryDisplay);
mWriter->selectLayer(layer);
// clang-format off
const std::array<float, 16> matrix = {{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
}};
// clang-format on
mWriter->setLayerColorTransform(matrix.data());
execute();
}
} // namespace
} // namespace vts
} // namespace V2_3