SurfaceFlinger: fix color transfer test
Add support for color management in
LayerTransactionTest.SetColorTransformBasic.
If color management is enabled, some considerations are needed
for the expected color output.
Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test
Change-Id: I7be7d561e7683fd57db0519932c4c308a6350c0d
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index cf9d4c5..cc0a307 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -583,6 +583,21 @@
}
return error;
}
+
+ virtual bool isColorManagementUsed() const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply);
+ int32_t result = 0;
+ status_t err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ ALOGE("ISurfaceComposer::isColorManagementUsed: error "
+ "retrieving result: %s (%d)",
+ strerror(-err), -err);
+ return false;
+ }
+ return result != 0;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -920,6 +935,12 @@
}
return NO_ERROR;
}
+ case IS_COLOR_MANAGEMET_USED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t result = isColorManagementUsed() ? 1 : 0;
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 781e062..35cb3be 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -282,6 +282,8 @@
virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
ui::PixelFormat* pixelFormat) const = 0;
+
+ virtual bool isColorManagementUsed() const = 0;
};
// ----------------------------------------------------------------------------
@@ -320,6 +322,7 @@
GET_LAYER_DEBUG_INFO,
CREATE_SCOPED_CONNECTION,
GET_COMPOSITION_PREFERENCE,
+ IS_COLOR_MANAGEMET_USED,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 500df05..25f762b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -633,6 +633,8 @@
return NO_ERROR;
}
+ virtual bool isColorManagementUsed() const { return false; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ab07bc6..fc8ca54 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -513,6 +513,10 @@
return mDisplayTokens[id];
}
+bool SurfaceFlinger::isColorManagementUsed() const {
+ return useColorManagement;
+}
+
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
@@ -4744,6 +4748,7 @@
case SET_TRANSACTION_STATE:
// Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
case CREATE_SCOPED_CONNECTION:
+ case IS_COLOR_MANAGEMET_USED:
case GET_COMPOSITION_PREFERENCE: {
return OK;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9e47b3f..73c9d95 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -462,6 +462,7 @@
virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
status_t getCompositionPreference(ui::Dataspace* outDataSpace,
ui::PixelFormat* outPixelFormat) const override;
+ virtual bool isColorManagementUsed() const;
/* ------------------------------------------------------------------------
* DeathRecipient interface
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 3166a8c..c814142 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -30,6 +30,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <ui/ColorSpace.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -314,6 +315,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mColorManagementUsed = sf->isColorManagementUsed();
}
virtual void TearDown() {
@@ -470,6 +475,8 @@
void setMatrixWithResizeHelper(uint32_t layerType);
sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
private:
void SetUpDisplay() {
mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -2064,6 +2071,47 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+
TEST_F(LayerTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(
@@ -2076,19 +2124,35 @@
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- const Color expected = {90, 90, 90, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
+ half3 expected = color;
mat3 matrix;
matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
Transaction().setColor(colorLayer, color)
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}