[RenderEngine] Polish shader pipeline for HDR support.
am: a296b0c232
Change-Id: I50968ef0cf5f2dd7ec3e8ea87bce32fe4a044253
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 0ccdbc4..c218e4d 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -52,9 +52,30 @@
}
void Description::setColorMatrix(const mat4& mtx) {
- const mat4 identity;
mColorMatrix = mtx;
- mColorMatrixEnabled = (mtx != identity);
+}
+
+void Description::setInputTransformMatrix(const mat3& matrix) {
+ mInputTransformMatrix = matrix;
+}
+
+void Description::setOutputTransformMatrix(const mat4& matrix) {
+ mOutputTransformMatrix = matrix;
+}
+
+bool Description::hasInputTransformMatrix() const {
+ const mat3 identity;
+ return mInputTransformMatrix != identity;
+}
+
+bool Description::hasOutputTransformMatrix() const {
+ const mat4 identity;
+ return mOutputTransformMatrix != identity;
+}
+
+bool Description::hasColorMatrix() const {
+ const mat4 identity;
+ return mColorMatrix != identity;
}
const mat4& Description::getColorMatrix() const {
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index b09e3a8..6ebb340 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -43,6 +43,11 @@
void setColor(const half4& color);
void setProjectionMatrix(const mat4& mtx);
void setColorMatrix(const mat4& mtx);
+ void setInputTransformMatrix(const mat3& matrix);
+ void setOutputTransformMatrix(const mat4& matrix);
+ bool hasInputTransformMatrix() const;
+ bool hasOutputTransformMatrix() const;
+ bool hasColorMatrix() const;
const mat4& getColorMatrix() const;
void setY410BT2020(bool enable);
@@ -72,11 +77,6 @@
// color used when texturing is disabled or when setting alpha.
half4 mColor;
- // projection matrix
- mat4 mProjectionMatrix;
-
- bool mColorMatrixEnabled = false;
- mat4 mColorMatrix;
// true if the sampled pixel values are in Y410/BT2020 rather than RGBA
bool mY410BT2020 = false;
@@ -86,6 +86,12 @@
TransferFunction mOutputTransferFunction = TransferFunction::LINEAR;
float mDisplayMaxLuminance;
+
+ // projection matrix
+ mat4 mProjectionMatrix;
+ mat4 mColorMatrix;
+ mat3 mInputTransformMatrix;
+ mat4 mOutputTransformMatrix;
};
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8e3c837..08cd5b0 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -131,15 +131,24 @@
// mColorBlindnessCorrection = M;
if (mPlatformHasWideColor) {
- // Compute sRGB to DisplayP3 color transform
- // NOTE: For now, we are limiting wide-color support to
- // Display-P3 only.
- mSrgbToDisplayP3 = mat4(
- ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform());
+ ColorSpace srgb(ColorSpace::sRGB());
+ ColorSpace displayP3(ColorSpace::DisplayP3());
+ ColorSpace bt2020(ColorSpace::BT2020());
- // Compute BT2020 to DisplayP3 color transform
- mBt2020ToDisplayP3 = mat4(
- ColorSpaceConnector(ColorSpace::BT2020(), ColorSpace::DisplayP3()).getTransform());
+ // Compute sRGB to Display P3 transform matrix.
+ // NOTE: For now, we are limiting output wide color space support to
+ // Display-P3 only.
+ mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
+
+ // Compute Display P3 to sRGB transform matrix.
+ mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+
+ // no chromatic adaptation needed since all color spaces use D65 for their white points.
+ mSrgbToXyz = srgb.getRGBtoXYZ();
+ mDisplayP3ToXyz = displayP3.getRGBtoXYZ();
+ mBt2020ToXyz = bt2020.getRGBtoXYZ();
+ mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
+ mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
}
}
@@ -307,44 +316,96 @@
glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
mesh.getByteStride(), mesh.getPositions());
- // TODO(b/73825729) Refactor this code block to handle BT2020 color space properly.
- // DISPLAY_P3 is the only supported wide color output
- if (mPlatformHasWideColor && mOutputDataSpace == Dataspace::DISPLAY_P3) {
+ // By default, DISPLAY_P3 is the only supported wide color output. However,
+ // when HDR content is present, hardware composer may be able to handle
+ // BT2020 data space, in that case, the output data space is set to be
+ // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
+ // to respect this and convert non-HDR content to HDR format.
+ if (mPlatformHasWideColor) {
Description wideColorState = mState;
- switch (mDataSpace) {
- case Dataspace::DISPLAY_P3:
- // input matches output
- break;
- case Dataspace::BT2020_PQ:
- case Dataspace::BT2020_ITU_PQ:
- wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
- wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
- wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
- break;
- case Dataspace::BT2020_HLG:
- case Dataspace::BT2020_ITU_HLG:
- wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
- wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
- wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
- break;
- default:
- // treat all other dataspaces as sRGB
- wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
- switch (static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK)) {
- case Dataspace::TRANSFER_LINEAR:
- wideColorState.setInputTransferFunction(
- Description::TransferFunction::LINEAR);
- break;
- default:
- // treat all other transfer functions as sRGB
- wideColorState.setInputTransferFunction(
- Description::TransferFunction::SRGB);
- break;
- }
- wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
- ALOGV("drawMesh: gamut transform applied");
- break;
+ Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
+ Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+ Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::STANDARD_MASK);
+ Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::TRANSFER_MASK);
+ bool needsXYZConversion = needsXYZTransformMatrix();
+
+ if (needsXYZConversion) {
+ // The supported input color spaces are standard RGB, Display P3 and BT2020.
+ switch (inputStandard) {
+ case Dataspace::STANDARD_DCI_P3:
+ wideColorState.setInputTransformMatrix(mDisplayP3ToXyz);
+ break;
+ case Dataspace::STANDARD_BT2020:
+ wideColorState.setInputTransformMatrix(mBt2020ToXyz);
+ break;
+ default:
+ wideColorState.setInputTransformMatrix(mSrgbToXyz);
+ break;
+ }
+
+ // The supported output color spaces are Display P3 and BT2020.
+ switch (outputStandard) {
+ case Dataspace::STANDARD_BT2020:
+ wideColorState.setOutputTransformMatrix(mXyzToBt2020);
+ break;
+ default:
+ wideColorState.setOutputTransformMatrix(mXyzToDisplayP3);
+ break;
+ }
+ } else if (inputStandard != outputStandard) {
+ // At this point, the input data space and output data space could be both
+ // HDR data spaces, but they match each other, we do nothing in this case.
+ // In addition to the case above, the input data space could be
+ // - scRGB linear
+ // - scRGB non-linear
+ // - sRGB
+ // - Display P3
+ // The output data spaces could be
+ // - sRGB
+ // - Display P3
+ if (outputStandard == Dataspace::STANDARD_BT709) {
+ wideColorState.setOutputTransformMatrix(mDisplayP3ToSrgb);
+ } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
+ wideColorState.setOutputTransformMatrix(mSrgbToDisplayP3);
+ }
}
+
+ // we need to convert the RGB value to linear space and convert it back when:
+ // - there is a color matrix that is not an identity matrix, or
+ // - there is an output transform matrix that is not an identity matrix, or
+ // - the input transfer function doesn't match the output transfer function.
+ if (wideColorState.hasColorMatrix() || wideColorState.hasOutputTransformMatrix() ||
+ inputTransfer != outputTransfer) {
+ switch (inputTransfer) {
+ case Dataspace::TRANSFER_ST2084:
+ wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
+ break;
+ case Dataspace::TRANSFER_HLG:
+ wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
+ break;
+ case Dataspace::TRANSFER_LINEAR:
+ wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+ break;
+ default:
+ wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+ break;
+ }
+
+ switch (outputTransfer) {
+ case Dataspace::TRANSFER_ST2084:
+ wideColorState.setOutputTransferFunction(Description::TransferFunction::ST2084);
+ break;
+ case Dataspace::TRANSFER_HLG:
+ wideColorState.setOutputTransferFunction(Description::TransferFunction::HLG);
+ break;
+ default:
+ wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+ break;
+ }
+ }
+
ProgramCache::getInstance().useProgram(wideColorState);
glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
@@ -373,6 +434,33 @@
dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
}
+bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
+ const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
+ const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
+ return standard == Dataspace::STANDARD_BT2020 &&
+ (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+}
+
+// For convenience, we want to convert the input color space to XYZ color space first,
+// and then convert from XYZ color space to output color space when
+// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
+// HDR content will be tone-mapped to SDR; Or,
+// - there are HDR PQ and HLG contents presented at the same time, where we want to convert
+// HLG content to PQ content.
+// In either case above, we need to operate the Y value in XYZ color space. Thus, when either
+// input data space or output data space is HDR data space, and the input transfer function
+// doesn't match the output transfer function, we would enable an intermediate transfrom to
+// XYZ color space.
+bool GLES20RenderEngine::needsXYZTransformMatrix() const {
+ const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
+ const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
+ const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+ const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+ Dataspace::TRANSFER_MASK);
+
+ return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
+}
+
// ---------------------------------------------------------------------------
} // namespace impl
} // namespace RE
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 7177aad..9acd79b 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -98,7 +98,18 @@
// Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
const bool mPlatformHasWideColor = false;
mat4 mSrgbToDisplayP3;
- mat4 mBt2020ToDisplayP3;
+ mat4 mDisplayP3ToSrgb;
+ mat3 mSrgbToXyz;
+ mat3 mBt2020ToXyz;
+ mat3 mDisplayP3ToXyz;
+ mat4 mXyzToDisplayP3;
+ mat4 mXyzToBt2020;
+
+private:
+ // A data space is considered HDR data space if it has BT2020 color space
+ // with PQ or HLG transfer function.
+ bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
+ bool needsXYZTransformMatrix() const;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index e5261c2..fd2c968 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -58,13 +58,13 @@
mVertexShader = vertexId;
mFragmentShader = fragmentId;
mInitialized = true;
-
- mColorMatrixLoc = glGetUniformLocation(programId, "colorMatrix");
mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
mSamplerLoc = glGetUniformLocation(programId, "sampler");
mColorLoc = glGetUniformLocation(programId, "color");
mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
+ mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
+ mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
// set-up the default values for our uniforms
glUseProgram(programId);
@@ -134,8 +134,16 @@
const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a};
glUniform4fv(mColorLoc, 1, color);
}
- if (mColorMatrixLoc >= 0) {
- glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
+ if (mInputTransformMatrixLoc >= 0) {
+ glUniformMatrix3fv(mInputTransformMatrixLoc, 1, GL_FALSE,
+ desc.mInputTransformMatrix.asArray());
+ }
+ if (mOutputTransformMatrixLoc >= 0) {
+ // The output transform matrix and color matrix can be combined as one matrix
+ // that is applied right before applying OETF.
+ mat4 outputTransformMatrix = desc.mColorMatrix * desc.mOutputTransformMatrix;
+ glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
+ outputTransformMatrix.asArray());
}
if (mDisplayMaxLuminanceLoc >= 0) {
glUniform1f(mDisplayMaxLuminanceLoc, desc.mDisplayMaxLuminance);
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 55b9cdd..ae796c5 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -69,9 +69,6 @@
/* location of the projection matrix uniform */
GLint mProjectionMatrixLoc;
- /* location of the color matrix uniform */
- GLint mColorMatrixLoc;
-
/* location of the texture matrix uniform */
GLint mTextureMatrixLoc;
@@ -83,6 +80,10 @@
/* location of display luminance uniform */
GLint mDisplayMaxLuminanceLoc;
+
+ /* location of transform matrix */
+ GLint mInputTransformMatrixLoc;
+ GLint mOutputTransformMatrixLoc;
};
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 5d5462f..89ee64b 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -125,13 +125,17 @@
description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
.set(Key::OPACITY_MASK,
description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
- .set(Key::COLOR_MATRIX_MASK,
- description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF);
+ .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
+ description.hasInputTransformMatrix() ?
+ Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
+ .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
+ description.hasOutputTransformMatrix() || description.hasColorMatrix() ?
+ Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
needs.set(Key::Y410_BT2020_MASK,
description.mY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
- if (needs.hasColorMatrix()) {
+ if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
switch (description.mInputTransferFunction) {
case Description::TransferFunction::LINEAR:
default:
@@ -441,13 +445,44 @@
)__SHADER__";
}
- if (needs.hasColorMatrix()) {
- fs << "uniform mat4 colorMatrix;";
+ if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
// Currently, only the OOTF of BT2020 PQ needs display maximum luminance.
if (needs.getInputTF() == Key::INPUT_TF_ST2084) {
fs << "uniform float displayMaxLuminance";
}
+ if (needs.hasInputTransformMatrix()) {
+ fs << "uniform mat3 inputTransformMatrix;";
+ fs << R"__SHADER__(
+ highp vec3 InputTransform(const highp vec3 color) {
+ return inputTransformMatrix * color;
+ }
+ )__SHADER__";
+ } else {
+ fs << R"__SHADER__(
+ highp vec3 InputTransform(const highp vec3 color) {
+ return color;
+ }
+ )__SHADER__";
+ }
+
+ // the transformation from a wider colorspace to a narrower one can
+ // result in >1.0 or <0.0 pixel values
+ if (needs.hasOutputTransformMatrix()) {
+ fs << "uniform mat4 outputTransformMatrix;";
+ fs << R"__SHADER__(
+ highp vec3 OutputTransform(const highp vec3 color) {
+ return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
+ }
+ )__SHADER__";
+ } else {
+ fs << R"__SHADER__(
+ highp vec3 OutputTransform(const highp vec3 color) {
+ return clamp(color, 0.0, 1.0);
+ }
+ )__SHADER__";
+ }
+
generateEOTF(fs, needs);
generateOOTF(fs, needs);
generateOETF(fs, needs);
@@ -476,18 +511,13 @@
}
}
- if (needs.hasColorMatrix()) {
+ if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
if (!needs.isOpaque() && needs.isPremultiplied()) {
// un-premultiply if needed before linearization
// avoid divide by 0 by adding 0.5/256 to the alpha channel
fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
- fs << "vec4 transformed = colorMatrix * vec4(OOTF(EOTF(gl_FragColor.rgb)), 1);";
- // the transformation from a wider colorspace to a narrower one can
- // result in >1.0 or <0.0 pixel values
- fs << "transformed.rgb = clamp(transformed.rgb, 0.0, 1.0);";
- // We assume the last row is always {0,0,0,1} and we skip the division by w
- fs << "gl_FragColor.rgb = OETF(transformed.rgb);";
+ fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index d18163a..e1398eb 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -72,26 +72,31 @@
TEXTURE_EXT = 1 << TEXTURE_SHIFT,
TEXTURE_2D = 2 << TEXTURE_SHIFT,
- COLOR_MATRIX_SHIFT = 5,
- COLOR_MATRIX_MASK = 1 << COLOR_MATRIX_SHIFT,
- COLOR_MATRIX_OFF = 0 << COLOR_MATRIX_SHIFT,
- COLOR_MATRIX_ON = 1 << COLOR_MATRIX_SHIFT,
+ INPUT_TRANSFORM_MATRIX_SHIFT = 5,
+ INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
+ INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
+ INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
- INPUT_TF_SHIFT = 6,
+ OUTPUT_TRANSFORM_MATRIX_SHIFT = 6,
+ OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+ OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+ OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+
+ INPUT_TF_SHIFT = 7,
INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
- OUTPUT_TF_SHIFT = 8,
+ OUTPUT_TF_SHIFT = 9,
OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
- Y410_BT2020_SHIFT = 10,
+ Y410_BT2020_SHIFT = 11,
Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
@@ -110,7 +115,15 @@
inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
- inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; }
+ inline bool hasInputTransformMatrix() const {
+ return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
+ }
+ inline bool hasOutputTransformMatrix() const {
+ return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
+ }
+ inline bool hasTransformMatrix() const {
+ return hasInputTransformMatrix() || hasOutputTransformMatrix();
+ }
inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }