graphics: Add display color sampling interface.

Add a graphics.composer@2.3 interface that will expose
color sampling hardware present on some devices to the
framework. Adds:
  getDisplayedContentSamplingAttributes
  setDisplayedContentSamplingEnabled
  getDisplayedContentSample

Test: boot up pixel3
Test: VtsHalGraphicsComposerV2_3TargetTest on revved Pixel3 hwcomposer
Bug: 116028976
Change-Id: I88455f200590926f677c47efc39e9b6678e2318c
This commit is contained in:
Kevin DuBois 2018-09-10 09:07:54 -07:00
parent 1028dd74bf
commit bf141483fa
7 changed files with 352 additions and 0 deletions

View file

@ -161,6 +161,116 @@ interface IComposerClient extends @2.2::IComposerClient {
Dataspace dataspace)
generates (Error error);
enum FormatColorComponent : uint8_t {
/* The first component (eg, for RGBA_8888, this is R) */
FORMAT_COMPONENT_0 = 1 << 0,
/* The second component (eg, for RGBA_8888, this is G) */
FORMAT_COMPONENT_1 = 1 << 1,
/* The third component (eg, for RGBA_8888, this is B) */
FORMAT_COMPONENT_2 = 1 << 2,
/* The fourth component (eg, for RGBA_8888, this is A) */
FORMAT_COMPONENT_3 = 1 << 3,
};
/**
* Query for what types of color sampling the hardware supports.
*
* @param display is the display where the samples are collected.
* @return error is NONE upon success. Otherwise,
* BAD_DISPLAY when an invalid display was passed in, or
* UNSUPPORTED when there is no efficient way to sample.
* @return format The format of the sampled pixels.
* @return dataspace The dataspace of the sampled pixels.
* @return componentMask The mask of which components can be sampled.
*/
getDisplayedContentSamplingAttributes(Display display)
generates (Error error,
PixelFormat format,
Dataspace dataspace,
bitfield<FormatColorComponent> componentMask);
/** DisplayedContentSampling values passed to setDisplayedContentSamplingEnabled. */
enum DisplayedContentSampling : int32_t {
INVALID = 0,
/** Enable content sampling. */
ENABLE = 1,
/** Disable content sampling. */
DISABLE = 2,
};
/**
* Enables or disables the collection of color content statistics
* on this display.
*
* Sampling occurs on the contents of the final composition on this display
* (i.e., the contents presented on screen). Samples should be collected after all
* color transforms have been applied.
*
* Sampling support is optional, and is set to DISABLE by default.
* On each call to ENABLE, all collected statistics must be reset.
*
* Sample data can be queried via getDisplayedContentSample().
*
* @param display is the display to which the sampling mode is set.
* @param enabled indicates whether to enable or disable sampling.
* @param componentMask The mask of which components should be sampled. If zero, all supported
* components are to be enabled.
* @param maxFrames is the maximum number of frames that should be stored before discard.
* The sample represents the most-recently posted frames.
* @return error is NONE upon success. Otherwise,
* BAD_DISPLAY when an invalid display handle was passed in,
* BAD_PARAMETER when enabled was an invalid value, or
* NO_RESOURCES when the requested ringbuffer size via maxFrames was
* not available.
* UNSUPPORTED when there is no efficient way to sample.
*/
setDisplayedContentSamplingEnabled(
Display display, DisplayedContentSampling enable,
bitfield<FormatColorComponent> componentMask, uint64_t maxFrames)
generates (Error error);
/**
* Collects the results of display content color sampling for display.
*
* Collection of data can occur whether the sampling is in ENABLE or
* DISABLE state.
*
* @param display is the display to which the sampling is collected.
* @param maxFrames is the maximum number of frames that should be represented in the sample.
* The sample represents the most-recently posted frames.
* If maxFrames is 0, all frames are to be represented by the sample.
* @param timestamp is the timestamp after which any frames were posted that should be
* included in the sample. Timestamp is CLOCK_MONOTONIC.
* If timestamp is 0, do not filter from the sample by time.
* @return error is NONE upon success. Otherwise,
* BAD_DISPLAY when an invalid display was passed in, or
* UNSUPPORTED when there is no efficient way to sample, or
* BAD_PARAMETER when the component is not supported by the hardware.
* @return frameCount The number of frames represented by this sample.
* @return sampleComponent0 is a histogram counting how many times a pixel of a given value
* was displayed onscreen for FORMAT_COMPONENT_0.
* The buckets of the histogram are evenly weighted, the number of buckets
* is device specific.
* eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
* 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
* were displayed onscreen in range 0x40->0x7F, etc.
* @return sampleComponent1 is the same sample definition as sampleComponent0,
* but for FORMAT_COMPONENT_1.
* @return sampleComponent2 is the same sample definition as sampleComponent0,
* but for FORMAT_COMPONENT_2.
* @return sampleComponent3 is the same sample definition as sampleComponent0,
* but for FORMAT_COMPONENT_3.
*/
getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp)
generates (Error error,
uint64_t frameCount,
vec<uint64_t> sampleComponent0,
vec<uint64_t> sampleComponent1,
vec<uint64_t> sampleComponent2,
vec<uint64_t> sampleComponent3);
/**
* Executes commands from the input command message queue. Return values
* generated by the input commands are written to the output command

View file

@ -91,6 +91,42 @@ class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interfac
return Void();
}
Return<void> getDisplayedContentSamplingAttributes(
uint64_t display,
IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override {
common::V1_1::PixelFormat format;
common::V1_2::Dataspace dataspace;
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask;
Error error =
mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask);
hidl_cb(error, format, dataspace, componentMask);
return Void();
}
Return<Error> setDisplayedContentSamplingEnabled(
uint64_t display, IComposerClient::DisplayedContentSampling enable,
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
uint64_t maxFrames) override {
return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
}
Return<void> getDisplayedContentSample(
uint64_t display, uint64_t maxFrames, uint64_t timestamp,
IComposerClient::getDisplayedContentSample_cb hidl_cb) override {
uint64_t frameCount;
hidl_vec<uint64_t> sampleComponent0;
hidl_vec<uint64_t> sampleComponent1;
hidl_vec<uint64_t> sampleComponent2;
hidl_vec<uint64_t> sampleComponent3;
Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount,
sampleComponent0, sampleComponent1,
sampleComponent2, sampleComponent3);
hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2,
sampleComponent3);
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);

View file

@ -72,6 +72,18 @@ class ComposerHal : public V2_2::hal::ComposerHal {
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;
virtual Error getDisplayedContentSamplingAttributes(
uint64_t display, PixelFormat& format, Dataspace& dataspace,
hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) = 0;
virtual Error setDisplayedContentSamplingEnabled(
uint64_t display, IComposerClient::DisplayedContentSampling enable,
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) = 0;
virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
uint64_t timestamp, uint64_t& frameCount,
hidl_vec<uint64_t>& sampleComponent0,
hidl_vec<uint64_t>& sampleComponent1,
hidl_vec<uint64_t>& sampleComponent2,
hidl_vec<uint64_t>& sampleComponent3) = 0;
};
} // namespace hal

View file

@ -104,6 +104,65 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
return static_cast<Error>(err);
}
Error getDisplayedContentSamplingAttributes(
uint64_t display, PixelFormat& format, Dataspace& dataspace,
hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) override {
if (!mDispatch.getDisplayedContentSamplingAttributes) {
return Error::UNSUPPORTED;
}
int32_t formatRaw = 0;
int32_t dataspaceRaw = 0;
uint8_t componentMaskRaw = 0;
int32_t errorRaw = mDispatch.getDisplayedContentSamplingAttributes(
mDevice, display, &formatRaw, &dataspaceRaw, &componentMaskRaw);
auto error = static_cast<Error>(errorRaw);
if (error == Error::NONE) {
format = static_cast<PixelFormat>(formatRaw);
dataspace = static_cast<Dataspace>(dataspaceRaw);
componentMask =
static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(componentMaskRaw);
}
return error;
};
Error setDisplayedContentSamplingEnabled(
uint64_t display, IComposerClient::DisplayedContentSampling enable,
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
uint64_t maxFrames) override {
if (!mDispatch.setDisplayedContentSamplingEnabled) {
return Error::UNSUPPORTED;
}
return static_cast<Error>(mDispatch.setDisplayedContentSamplingEnabled(
mDevice, display, static_cast<int32_t>(enable), componentMask, maxFrames));
}
Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
hidl_vec<uint64_t>& sampleComponent1,
hidl_vec<uint64_t>& sampleComponent2,
hidl_vec<uint64_t>& sampleComponent3) override {
if (!mDispatch.getDisplayedContentSample) {
return Error::UNSUPPORTED;
}
int32_t size[4] = {0};
auto errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
&frameCount, size, nullptr);
if (errorRaw != HWC2_ERROR_NONE) {
return static_cast<Error>(errorRaw);
}
sampleComponent0.resize(size[0]);
sampleComponent1.resize(size[1]);
sampleComponent2.resize(size[2]);
sampleComponent3.resize(size[3]);
uint64_t* samples[] = {sampleComponent0.data(), sampleComponent1.data(),
sampleComponent2.data(), sampleComponent3.data()};
errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
&frameCount, size, samples);
return static_cast<Error>(errorRaw);
}
protected:
bool initDispatch() override {
if (!BaseType2_2::initDispatch()) {
@ -114,6 +173,12 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
&mDispatch.getDisplayIdentificationData);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
&mDispatch.setLayerColorTransform);
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
&mDispatch.getDisplayedContentSamplingAttributes);
this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED,
&mDispatch.setDisplayedContentSamplingEnabled);
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
&mDispatch.getDisplayedContentSample);
return true;
}
@ -121,6 +186,9 @@ class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
struct {
HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES getDisplayedContentSamplingAttributes;
HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled;
HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample;
} mDispatch = {};
using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;

View file

@ -108,6 +108,48 @@ bool ComposerClient::getClientTargetSupport_2_3(Display display, uint32_t width,
return error == Error::NONE;
}
Error ComposerClient::getDisplayedContentSamplingAttributes(
uint64_t display, PixelFormat& format, Dataspace& dataspace,
hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
auto error = Error::BAD_PARAMETER;
mClient->getDisplayedContentSamplingAttributes(
display, [&](const auto& tmpError, const auto& tmpFormat, const auto& tmpDataspace,
const auto& tmpComponentMask) {
error = tmpError;
format = tmpFormat;
dataspace = tmpDataspace;
componentMask = tmpComponentMask;
});
return error;
}
Error ComposerClient::setDisplayedContentSamplingEnabled(
uint64_t display, IComposerClient::DisplayedContentSampling enable,
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) {
return mClient->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
}
Error ComposerClient::getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
uint64_t timestamp, uint64_t& frameCount,
hidl_vec<uint64_t>& sampleComponent0,
hidl_vec<uint64_t>& sampleComponent1,
hidl_vec<uint64_t>& sampleComponent2,
hidl_vec<uint64_t>& sampleComponent3) {
auto error = Error::BAD_PARAMETER;
mClient->getDisplayedContentSample(
display, maxFrames, timestamp,
[&](const auto& tmpError, const auto& tmpFrameCount, const auto& tmpSamples0,
const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) {
error = tmpError;
frameCount = tmpFrameCount;
sampleComponent0 = tmpSamples0;
sampleComponent1 = tmpSamples1;
sampleComponent2 = tmpSamples2;
sampleComponent3 = tmpSamples3;
});
return error;
}
} // namespace vts
} // namespace V2_3
} // namespace composer

View file

@ -37,6 +37,7 @@ using common::V1_1::RenderIntent;
using common::V1_2::ColorMode;
using common::V1_2::Dataspace;
using V2_1::Display;
using V2_1::Error;
using V2_3::IComposer;
using V2_3::IComposerClient;
@ -67,6 +68,17 @@ class ComposerClient : public V2_2::vts::ComposerClient {
bool getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData);
Error getDisplayedContentSamplingAttributes(
uint64_t display, PixelFormat& format, Dataspace& dataspace,
hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask);
Error setDisplayedContentSamplingEnabled(
uint64_t display, IComposerClient::DisplayedContentSampling enable,
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames);
Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
hidl_vec<uint64_t>& sampleComponent1,
hidl_vec<uint64_t>& sampleComponent2,
hidl_vec<uint64_t>& sampleComponent3);
std::vector<ColorMode> getColorModes_2_3(Display display);

View file

@ -355,6 +355,78 @@ TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
execute();
}
TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
using common::V1_1::PixelFormat;
using common::V1_2::Dataspace;
int constexpr invalid = -1;
auto format = static_cast<PixelFormat>(invalid);
auto dataspace = static_cast<Dataspace>(invalid);
auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
dataspace, componentMask);
if (error == Error::UNSUPPORTED) {
SUCCEED() << "Device does not support optional extension. Test skipped";
return;
}
EXPECT_EQ(error, Error::NONE);
EXPECT_NE(format, static_cast<PixelFormat>(invalid));
EXPECT_NE(dataspace, static_cast<Dataspace>(invalid));
EXPECT_NE(componentMask,
static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
};
TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
auto const maxFrames = 10;
auto const enableAllComponents = 0;
auto error = mComposerClient->setDisplayedContentSamplingEnabled(
mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents,
maxFrames);
if (error == Error::UNSUPPORTED) {
SUCCEED() << "Device does not support optional extension. Test skipped";
return;
}
EXPECT_EQ(error, Error::NONE);
error = mComposerClient->setDisplayedContentSamplingEnabled(
mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents,
maxFrames);
EXPECT_EQ(error, Error::NONE);
}
TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
int constexpr invalid = -1;
auto format = static_cast<PixelFormat>(invalid);
auto dataspace = static_cast<Dataspace>(invalid);
auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
dataspace, componentMask);
uint64_t maxFrames = 10;
uint64_t timestamp = 0;
uint64_t frameCount = 0;
hidl_array<hidl_vec<uint64_t>, 4> histogram;
error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp,
frameCount, histogram[0], histogram[1],
histogram[2], histogram[3]);
if (error == Error::UNSUPPORTED) {
SUCCEED() << "Device does not support optional extension. Test skipped";
return;
}
EXPECT_EQ(error, Error::NONE);
EXPECT_LE(frameCount, maxFrames);
for (auto i = 0; i < histogram.size(); i++) {
if (componentMask & (1 << i)) {
EXPECT_NE(histogram[i].size(), 0);
} else {
EXPECT_EQ(histogram[i].size(), 0);
}
}
}
} // namespace
} // namespace vts
} // namespace V2_3