diff options
| author | 2016-11-10 11:45:58 -0800 | |
|---|---|---|
| committer | 2016-11-10 13:06:18 -0800 | |
| commit | caf2ca414f69d460c516e2370cf42bcf49178d95 (patch) | |
| tree | b0fdcb86a20d2b779bbc728a6ba8481884b3bc9e | |
| parent | 5d4bae7f170640e0e280b3ca8a22b18e80801a8a (diff) | |
Add ColorSpace class
The ColorSpace class can be used to create an RGB color space from
either primaries/whitepoint or an RGB->XYZ matrix.
The primaries and whitepoint are in xyY space. A utility function
is provided to compute xyY coordinates from XYZ coordinats.
The class contains numerous functions to create common RGB color
spaces (sRGB, DCI-P3, etc.).
Test: colorspace_test
Bug: 29940137
Change-Id: Ifba8701377d058f5877176dabf4183e904a4cde0
| -rw-r--r-- | include/ui/ColorSpace.h | 192 | ||||
| -rw-r--r-- | include/ui/TMatHelpers.h | 40 | ||||
| -rw-r--r-- | include/ui/TVecHelpers.h | 50 | ||||
| -rw-r--r-- | include/ui/half.h | 43 | ||||
| -rw-r--r-- | include/ui/mat2.h | 48 | ||||
| -rw-r--r-- | include/ui/mat3.h | 58 | ||||
| -rw-r--r-- | include/ui/mat4.h | 96 | ||||
| -rw-r--r-- | include/ui/quat.h | 30 | ||||
| -rw-r--r-- | include/ui/scalar.h | 120 | ||||
| -rw-r--r-- | include/ui/vec2.h | 7 | ||||
| -rw-r--r-- | include/ui/vec3.h | 5 | ||||
| -rw-r--r-- | include/ui/vec4.h | 5 | ||||
| -rw-r--r-- | libs/ui/Android.bp | 1 | ||||
| -rw-r--r-- | libs/ui/ColorSpace.cpp | 241 | ||||
| -rw-r--r-- | libs/ui/tests/Android.bp | 6 | ||||
| -rw-r--r-- | libs/ui/tests/colorspace_test.cpp | 148 | ||||
| -rw-r--r-- | libs/ui/tests/half_test.cpp | 2 |
17 files changed, 816 insertions, 276 deletions
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h new file mode 100644 index 0000000000..2543e7fd78 --- /dev/null +++ b/include/ui/ColorSpace.h @@ -0,0 +1,192 @@ +/* + * 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. + */ + +#ifndef ANDROID_UI_COLOR_SPACE +#define ANDROID_UI_COLOR_SPACE + +#include <array> +#include <cmath> +#include <functional> +#include <string> + +#include <ui/mat3.h> +#include <ui/scalar.h> +#include <ui/vec2.h> +#include <ui/vec3.h> + +namespace android { + +class ColorSpace { +public: + typedef std::function<float(float)> transfer_function; + typedef std::function<float(float)> clamping_function; + + /** + * Creates a named color space with the specified RGB->XYZ + * conversion matrix. The white point and primaries will be + * computed from the supplied matrix. + * + * The default transfer functions are a linear response x->x + * and the default clamping function is a simple saturate + * (clamp(x, 0, 1)). + */ + ColorSpace( + const std::string& name, + const mat3& rgbToXYZ, + transfer_function OETF = linearReponse, + transfer_function EOTF = linearReponse, + clamping_function clamper = saturate<float> + ) noexcept; + + /** + * Creates a named color space with the specified primaries + * and white point. The RGB<>XYZ conversion matrices are + * computed from the primaries and white point. + * + * The default transfer functions are a linear response x->x + * and the default clamping function is a simple saturate + * (clamp(x, 0, 1)). + */ + ColorSpace( + const std::string& name, + const std::array<float2, 3>& primaries, + const float2& whitePoint, + transfer_function OETF = linearReponse, + transfer_function EOTF = linearReponse, + clamping_function clamper = saturate<float> + ) noexcept; + + ColorSpace() noexcept = delete; + + /** + * Encodes the supplied RGB value using this color space's + * opto-electronic transfer function. + */ + constexpr float3 fromLinear(const float3& v) const noexcept { + return apply(v, mOETF); + } + + /** + * Decodes the supplied RGB value using this color space's + * electro-optical transfer function. + */ + constexpr float3 toLinear(const float3& v) const noexcept { + return apply(v, mEOTF); + } + + /** + * Converts the supplied XYZ value to RGB. The returned value + * is encoded with this color space's opto-electronic transfer + * function and clamped by this color space's clamping function. + */ + constexpr float3 xyzToRGB(const float3& xyz) const noexcept { + return apply(fromLinear(mXYZtoRGB * xyz), mClamper); + } + + /** + * Converts the supplied RGB value to XYZ. The input RGB value + * is decoded using this color space's electro-optical function + * before being converted to XYZ. The returned result is clamped + * by this color space's clamping function. + */ + constexpr float3 rgbToXYZ(const float3& rgb) const noexcept { + return apply(mRGBtoXYZ * toLinear(rgb), mClamper); + } + + constexpr const std::string& getName() const noexcept { + return mName; + } + + constexpr const mat3& getRGBtoXYZ() const noexcept { + return mRGBtoXYZ; + } + + constexpr const mat3& getXYZtoRGB() const noexcept { + return mXYZtoRGB; + } + + constexpr const transfer_function& getOETF() const noexcept { + return mOETF; + } + + constexpr const transfer_function& getEOTF() const noexcept { + return mEOTF; + } + + constexpr const clamping_function& getClamper() const noexcept { + return mClamper; + } + + constexpr const std::array<float2, 3>& getPrimaries() const noexcept { + return mPrimaries; + } + + constexpr const float2& getWhitePoint() const noexcept { + return mWhitePoint; + } + + /** + * Converts the supplied XYZ value to xyY. + */ + static constexpr float2 xyY(const float3& XYZ) { + return XYZ.xy / dot(XYZ, float3{1}); + } + + /** + * Converts the supplied xyY value to XYZ. + */ + static constexpr float3 XYZ(const float3& xyY) { + return float3{(xyY.x * xyY.z) / xyY.y, xyY.z, ((1 - xyY.x - xyY.y) * xyY.z) / xyY.y}; + } + + static const ColorSpace sRGB(); + static const ColorSpace linearSRGB(); + static const ColorSpace extendedSRGB(); + static const ColorSpace linearExtendedSRGB(); + static const ColorSpace NTSC(); + static const ColorSpace BT709(); + static const ColorSpace BT2020(); + static const ColorSpace AdobeRGB(); + static const ColorSpace ProPhotoRGB(); + static const ColorSpace DisplayP3(); + static const ColorSpace DCIP3(); + static const ColorSpace ACES(); + static const ColorSpace ACEScg(); + +private: + static constexpr mat3 computeXYZMatrix( + const std::array<float2, 3>& primaries, const float2& whitePoint); + + static constexpr float linearReponse(float v) { + return v; + } + + const std::string mName; + + const mat3 mRGBtoXYZ; + const mat3 mXYZtoRGB; + + const transfer_function mOETF; + const transfer_function mEOTF; + const clamping_function mClamper; + + std::array<float2, 3> mPrimaries; + float2 mWhitePoint; +}; + +}; // namespace android + +#endif // ANDROID_UI_COLOR_SPACE diff --git a/include/ui/TMatHelpers.h b/include/ui/TMatHelpers.h index 9daca0827d..8edf5f82e3 100644 --- a/include/ui/TMatHelpers.h +++ b/include/ui/TMatHelpers.h @@ -41,6 +41,12 @@ #define PURE __attribute__((pure)) +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { namespace details { // ------------------------------------------------------------------------------------- @@ -103,10 +109,10 @@ MATRIX PURE gaussJordanInverse(const MATRIX& src) { // Factor out the lower triangle for (size_t j = 0; j < N; ++j) { if (j != i) { - const T t = tmp[j][i]; + const T d = tmp[j][i]; for (size_t k = 0; k < N; ++k) { - tmp[j][k] -= tmp[i][k] * t; - inverted[j][k] -= inverted[i][k] * t; + tmp[j][k] -= tmp[i][k] * d; + inverted[j][k] -= inverted[i][k] * d; } } } @@ -119,7 +125,7 @@ MATRIX PURE gaussJordanInverse(const MATRIX& src) { //------------------------------------------------------------------------------ // 2x2 matrix inverse is easy. template <typename MATRIX> -MATRIX PURE fastInverse2(const MATRIX& x) { +CONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) { typedef typename MATRIX::value_type T; // Assuming the input matrix is: @@ -153,7 +159,7 @@ MATRIX PURE fastInverse2(const MATRIX& x) { // matrix inversion: // http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices template <typename MATRIX> -MATRIX PURE fastInverse3(const MATRIX& x) { +CONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) { typedef typename MATRIX::value_type T; // Assuming the input matrix is: @@ -216,7 +222,6 @@ MATRIX PURE fastInverse3(const MATRIX& x) { return inverted; } - /** * Inversion function which switches on the matrix size. * @warning This function assumes the matrix is invertible. The result is @@ -232,7 +237,7 @@ inline constexpr MATRIX PURE inverse(const MATRIX& matrix) { } template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B> -MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { +CONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { // pre-requisite: // lhs : D columns, R rows // rhs : C columns, D rows @@ -254,7 +259,7 @@ MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { // transpose. this handles matrices of matrices template <typename MATRIX> -MATRIX PURE transpose(const MATRIX& m) { +CONSTEXPR MATRIX PURE transpose(const MATRIX& m) { // for now we only handle square matrix transpose static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices"); MATRIX result(MATRIX::NO_INIT); @@ -268,7 +273,7 @@ MATRIX PURE transpose(const MATRIX& m) { // trace. this handles matrices of matrices template <typename MATRIX> -typename MATRIX::value_type PURE trace(const MATRIX& m) { +CONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) { static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices"); typename MATRIX::value_type result(0); for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { @@ -279,7 +284,7 @@ typename MATRIX::value_type PURE trace(const MATRIX& m) { // diag. this handles matrices of matrices template <typename MATRIX> -typename MATRIX::col_type PURE diag(const MATRIX& m) { +CONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) { static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices"); typename MATRIX::col_type result(MATRIX::col_type::NO_INIT); for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { @@ -389,7 +394,7 @@ public: // matrix * matrix, result is a matrix of the same type than the lhs matrix template<typename U> - friend BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) { + friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) { return matrix::multiply<BASE<T> >(lhs, rhs); } }; @@ -419,7 +424,7 @@ public: * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE<T> being known). */ - friend inline BASE<T> PURE inverse(const BASE<T>& matrix) { + friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) { return matrix::inverse(matrix); } friend inline constexpr BASE<T> PURE transpose(const BASE<T>& m) { @@ -454,7 +459,7 @@ public: } template <typename VEC> - static BASE<T> translate(const VEC& t) { + static CONSTEXPR BASE<T> translate(const VEC& t) { BASE<T> r; r[BASE<T>::NUM_COLS-1] = t; return r; @@ -465,7 +470,7 @@ public: return BASE<T>(s); } - friend inline BASE<T> PURE abs(BASE<T> m) { + friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) { for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) { m[col] = abs(m[col]); } @@ -482,7 +487,7 @@ public: } template <typename A, typename VEC> - static BASE<T> rotate(A radian, const VEC& about) { + static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) { BASE<T> r; T c = std::cos(radian); T s = std::sin(radian); @@ -533,7 +538,7 @@ public: typename = typename std::enable_if<std::is_arithmetic<P>::value >::type, typename = typename std::enable_if<std::is_arithmetic<R>::value >::type > - static BASE<T> eulerYXZ(Y yaw, P pitch, R roll) { + static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) { return eulerZYX(roll, pitch, yaw); } @@ -552,7 +557,7 @@ public: typename = typename std::enable_if<std::is_arithmetic<P>::value >::type, typename = typename std::enable_if<std::is_arithmetic<R>::value >::type > - static BASE<T> eulerZYX(Y yaw, P pitch, R roll) { + static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) { BASE<T> r; T cy = std::cos(yaw); T sy = std::sin(yaw); @@ -630,5 +635,6 @@ public: #undef LIKELY #undef UNLIKELY #undef PURE +#undef CONSTEXPR #endif // UI_TMATHELPERS_H_ diff --git a/include/ui/TVecHelpers.h b/include/ui/TVecHelpers.h index 1eaa6e66e4..de1d9ffcc9 100644 --- a/include/ui/TVecHelpers.h +++ b/include/ui/TVecHelpers.h @@ -28,6 +28,12 @@ #define PURE __attribute__((pure)) +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { namespace details { // ------------------------------------------------------------------------------------- @@ -228,6 +234,7 @@ public: } return rhs; } + VECTOR<T>& operator --() { VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this); for (size_t i = 0; i < rhs.size(); i++) { @@ -235,7 +242,8 @@ public: } return rhs; } - VECTOR<T> operator -() const { + + CONSTEXPR VECTOR<T> operator -() const { VECTOR<T> r(VECTOR<T>::NO_INIT); VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this)); for (size_t i = 0; i < r.size(); i++) { @@ -333,7 +341,7 @@ public: * (the first one, BASE<T> being known). */ template<typename RT> - friend inline T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) { + friend inline CONSTEXPR T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) { T r(0); for (size_t i = 0; i < lv.size(); i++) { //r = std::fma(lv[i], rv[i], r); @@ -372,71 +380,71 @@ public: return lv * (T(1) / length(lv)); } - friend inline VECTOR<T> PURE rcp(VECTOR<T> v) { + friend inline constexpr VECTOR<T> PURE rcp(VECTOR<T> v) { return T(1) / v; } - friend inline VECTOR<T> PURE abs(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE abs(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::abs(v[i]); } return v; } - friend inline VECTOR<T> PURE floor(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE floor(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::floor(v[i]); } return v; } - friend inline VECTOR<T> PURE ceil(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE ceil(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::ceil(v[i]); } return v; } - friend inline VECTOR<T> PURE round(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE round(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::round(v[i]); } return v; } - friend inline VECTOR<T> PURE inversesqrt(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE inversesqrt(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = T(1) / std::sqrt(v[i]); } return v; } - friend inline VECTOR<T> PURE sqrt(VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE sqrt(VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::sqrt(v[i]); } return v; } - friend inline VECTOR<T> PURE pow(VECTOR<T> v, T p) { + friend inline CONSTEXPR VECTOR<T> PURE pow(VECTOR<T> v, T p) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::pow(v[i], p); } return v; } - friend inline VECTOR<T> PURE saturate(const VECTOR<T>& lv) { + friend inline CONSTEXPR VECTOR<T> PURE saturate(const VECTOR<T>& lv) { return clamp(lv, T(0), T(1)); } - friend inline VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) { + friend inline CONSTEXPR VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) { for (size_t i=0 ; i< v.size() ; i++) { v[i] = std::min(max, std::max(min, v[i])); } return v; } - friend inline VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) { + friend inline CONSTEXPR VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) { for (size_t i=0 ; i<lv.size() ; i++) { //a[i] = std::fma(lv[i], rv[i], a[i]); a[i] += (lv[i] * rv[i]); @@ -444,21 +452,21 @@ public: return a; } - friend inline VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::min(u[i], v[i]); } return v; } - friend inline VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) { + friend inline CONSTEXPR VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) { for (size_t i=0 ; i<v.size() ; i++) { v[i] = std::max(u[i], v[i]); } return v; } - friend inline T PURE max(const VECTOR<T>& v) { + friend inline CONSTEXPR T PURE max(const VECTOR<T>& v) { T r(std::numeric_limits<T>::lowest()); for (size_t i=0 ; i<v.size() ; i++) { r = std::max(r, v[i]); @@ -466,13 +474,20 @@ public: return r; } - friend inline T PURE min(const VECTOR<T>& v) { + friend inline CONSTEXPR T PURE min(const VECTOR<T>& v) { T r(std::numeric_limits<T>::max()); for (size_t i=0 ; i<v.size() ; i++) { r = std::min(r, v[i]); } return r; } + + friend inline CONSTEXPR VECTOR<T> PURE apply(VECTOR<T> v, const std::function<T(T)>& f) { + for (size_t i=0 ; i<v.size() ; i++) { + v[i] = f(v[i]); + } + return v; + } }; /* @@ -502,6 +517,7 @@ public: } }; +#undef CONSTEXPR #undef PURE // ------------------------------------------------------------------------------------- diff --git a/include/ui/half.h b/include/ui/half.h index cbc1ef022d..7a271dc57b 100644 --- a/include/ui/half.h +++ b/include/ui/half.h @@ -30,6 +30,12 @@ # define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) #endif +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { /* @@ -50,13 +56,13 @@ class half { struct fp16 { uint16_t bits = 0; fp16() noexcept = default; - explicit constexpr fp16(uint16_t bits) noexcept : bits(bits) { } + explicit constexpr fp16(uint16_t b) noexcept : bits(b) { } void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); } void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); } void setM(unsigned int s) noexcept { bits = uint16_t((bits & 0xFC00) | (s<< 0)); } - unsigned int getS() const noexcept { return bits >> 15u; } - unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; } - unsigned int getM() const noexcept { return bits & 0x3FFu; } + constexpr unsigned int getS() const noexcept { return bits >> 15u; } + constexpr unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; } + constexpr unsigned int getM() const noexcept { return bits & 0x3FFu; } }; struct fp32 { union { @@ -68,14 +74,14 @@ class half { void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); } void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); } void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); } - unsigned int getS() const noexcept { return bits >> 31u; } - unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; } - unsigned int getM() const noexcept { return bits & 0x7FFFFFu; } + constexpr unsigned int getS() const noexcept { return bits >> 31u; } + constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; } + constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; } }; public: - half(float v) noexcept : mBits(ftoh(v)) { } - operator float() const noexcept { return htof(mBits); } + CONSTEXPR half(float v) noexcept : mBits(ftoh(v)) { } + CONSTEXPR operator float() const noexcept { return htof(mBits); } uint16_t getBits() const noexcept { return mBits.bits; } unsigned int getExponent() const noexcept { return mBits.getE(); } @@ -83,23 +89,23 @@ public: private: friend class std::numeric_limits<half>; - friend half operator"" _hf(long double v); + friend CONSTEXPR half operator"" _hf(long double v); enum Binary { binary }; explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { } - static fp16 ftoh(float v) noexcept; - static float htof(fp16 v) noexcept; + static CONSTEXPR fp16 ftoh(float v) noexcept; + static CONSTEXPR float htof(fp16 v) noexcept; fp16 mBits; }; -inline /* constexpr */ half::fp16 half::ftoh(float v) noexcept { +inline CONSTEXPR half::fp16 half::ftoh(float v) noexcept { fp16 out; fp32 in(v); if (UNLIKELY(in.getE() == 0xFF)) { // inf or nan out.setE(0x1F); out.setM(in.getM() ? 0x200 : 0); } else { - int e = in.getE() - 127 + 15; + int e = static_cast<int>(in.getE()) - 127 + 15; if (e >= 0x1F) { // overflow out.setE(0x31); // +/- inf @@ -120,7 +126,7 @@ inline /* constexpr */ half::fp16 half::ftoh(float v) noexcept { return out; } -inline float half::htof(half::fp16 in) noexcept { +inline CONSTEXPR float half::htof(half::fp16 in) noexcept { fp32 out; if (UNLIKELY(in.getE() == 0x1F)) { // inf or nan out.setE(0xFF); @@ -132,7 +138,7 @@ inline float half::htof(half::fp16 in) noexcept { // (it's stupid because they can be represented as regular float) } } else { - int e = in.getE() - 15 + 127; + int e = static_cast<int>(in.getE()) - 15 + 127; unsigned int m = in.getM(); out.setE(uint32_t(e)); out.setM(m << 13); @@ -142,8 +148,8 @@ inline float half::htof(half::fp16 in) noexcept { return out.fp; } -inline /* constexpr */ android::half operator"" _hf(long double v) { - return android::half(android::half::binary, android::half::ftoh(v).bits); +inline CONSTEXPR android::half operator"" _hf(long double v) { + return android::half(android::half::binary, android::half::ftoh(static_cast<float>(v)).bits); } } // namespace android @@ -197,5 +203,6 @@ public: #undef LIKELY #undef UNLIKELY +#undef CONSTEXPR #endif // UI_HALF_H diff --git a/include/ui/mat2.h b/include/ui/mat2.h index 5ae73dcd59..37c7221b14 100644 --- a/include/ui/mat2.h +++ b/include/ui/mat2.h @@ -24,6 +24,12 @@ #define PURE __attribute__((pure)) +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { // ------------------------------------------------------------------------------------- namespace details { @@ -130,8 +136,7 @@ public: /** * leaves object uninitialized. use with caution. */ - explicit - constexpr TMat22(no_init) + explicit constexpr TMat22(no_init) : m_value{ col_type(col_type::NO_INIT), col_type(col_type::NO_INIT) } {} @@ -148,7 +153,7 @@ public: * \right) * \f$ */ - TMat22(); + CONSTEXPR TMat22(); /** * initialize to Identity*scalar. @@ -163,7 +168,7 @@ public: * \f$ */ template<typename U> - explicit TMat22(U v); + explicit CONSTEXPR TMat22(U v); /** * sets the diagonal to a vector. @@ -178,13 +183,13 @@ public: * \f$ */ template <typename U> - explicit TMat22(const TVec2<U>& v); + explicit CONSTEXPR TMat22(const TVec2<U>& v); /** * construct from another matrix of the same size */ template <typename U> - explicit TMat22(const TMat22<U>& rhs); + explicit CONSTEXPR TMat22(const TMat22<U>& rhs); /** * construct from 2 column vectors. @@ -198,7 +203,7 @@ public: * \f$ */ template <typename A, typename B> - TMat22(const TVec2<A>& v0, const TVec2<B>& v1); + CONSTEXPR TMat22(const TVec2<A>& v0, const TVec2<B>& v1); /** construct from 4 elements in column-major form. * @@ -214,19 +219,18 @@ public: template < typename A, typename B, typename C, typename D> - TMat22(A m00, B m01, - C m10, D m11); + CONSTEXPR TMat22(A m00, B m01, C m10, D m11); /** * construct from a C array in column major form. */ template <typename U> - explicit TMat22(U const* rawArray); + explicit CONSTEXPR TMat22(U const* rawArray); /** * Rotate by radians in the 2D plane */ - static TMat22<T> rotate(T radian) { + static CONSTEXPR TMat22<T> rotate(T radian) { TMat22<T> r(TMat22<T>::NO_INIT); T c = std::cos(radian); T s = std::sin(radian); @@ -244,21 +248,21 @@ public: // operations. template <typename T> -TMat22<T>::TMat22() { +CONSTEXPR TMat22<T>::TMat22() { m_value[0] = col_type(1, 0); m_value[1] = col_type(0, 1); } template <typename T> template <typename U> -TMat22<T>::TMat22(U v) { +CONSTEXPR TMat22<T>::TMat22(U v) { m_value[0] = col_type(v, 0); m_value[1] = col_type(0, v); } template<typename T> template<typename U> -TMat22<T>::TMat22(const TVec2<U>& v) { +CONSTEXPR TMat22<T>::TMat22(const TVec2<U>& v) { m_value[0] = col_type(v.x, 0); m_value[1] = col_type(0, v.y); } @@ -270,15 +274,14 @@ template<typename T> template < typename A, typename B, typename C, typename D> -TMat22<T>::TMat22(A m00, B m01, - C m10, D m11) { +CONSTEXPR TMat22<T>::TMat22( A m00, B m01, C m10, D m11) { m_value[0] = col_type(m00, m01); m_value[1] = col_type(m10, m11); } template <typename T> template <typename U> -TMat22<T>::TMat22(const TMat22<U>& rhs) { +CONSTEXPR TMat22<T>::TMat22(const TMat22<U>& rhs) { for (size_t col = 0; col < NUM_COLS; ++col) { m_value[col] = col_type(rhs[col]); } @@ -287,7 +290,7 @@ TMat22<T>::TMat22(const TMat22<U>& rhs) { // Construct from 2 column vectors. template <typename T> template <typename A, typename B> -TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) { +CONSTEXPR TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) { m_value[0] = v0; m_value[1] = v1; } @@ -295,7 +298,7 @@ TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) { // Construct from raw array, in column-major form. template <typename T> template <typename U> -TMat22<T>::TMat22(U const* rawArray) { +CONSTEXPR TMat22<T>::TMat22(U const* rawArray) { for (size_t col = 0; col < NUM_COLS; ++col) { for (size_t row = 0; row < NUM_ROWS; ++row) { m_value[col][row] = *rawArray++; @@ -317,7 +320,7 @@ TMat22<T>::TMat22(U const* rawArray) { // matrix * column-vector, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U>& rhs) { +CONSTEXPR typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U>& rhs) { // Result is initialized to zero. typename TMat22<U>::col_type result; for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) { @@ -328,7 +331,7 @@ typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U // row-vector * matrix, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat22<U>::row_type PURE operator *(const TVec2<U>& lhs, const TMat22<T>& rhs) { +CONSTEXPR typename TMat22<U>::row_type PURE operator *(const TVec2<U>& lhs, const TMat22<T>& rhs) { typename TMat22<U>::row_type result(TMat22<U>::row_type::NO_INIT); for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) { result[col] = dot(lhs, rhs[col]); @@ -356,7 +359,7 @@ operator*(U lhs, const TMat22<T>& rhs) { * BASE<T>::col_type is not accessible from there (???) */ template<typename T> -typename TMat22<T>::col_type PURE diag(const TMat22<T>& m) { +CONSTEXPR typename TMat22<T>::col_type PURE diag(const TMat22<T>& m) { return matrix::diag(m); } @@ -372,5 +375,6 @@ typedef details::TMat22<float> mat2f; } // namespace android #undef PURE +#undef CONSTEXPR #endif // UI_MAT2_H_ diff --git a/include/ui/mat3.h b/include/ui/mat3.h index 6a071c1aae..cd24a44d0e 100644 --- a/include/ui/mat3.h +++ b/include/ui/mat3.h @@ -25,6 +25,12 @@ #define PURE __attribute__((pure)) +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { // ------------------------------------------------------------------------------------- namespace details { @@ -137,8 +143,7 @@ public: /** * leaves object uninitialized. use with caution. */ - explicit - constexpr TMat33(no_init) + explicit constexpr TMat33(no_init) : m_value{ col_type(col_type::NO_INIT), col_type(col_type::NO_INIT), col_type(col_type::NO_INIT) } {} @@ -157,7 +162,7 @@ public: * \right) * \f$ */ - TMat33(); + CONSTEXPR TMat33(); /** * initialize to Identity*scalar. @@ -173,7 +178,7 @@ public: * \f$ */ template<typename U> - explicit TMat33(U v); + explicit CONSTEXPR TMat33(U v); /** * sets the diagonal to a vector. @@ -189,13 +194,13 @@ public: * \f$ */ template <typename U> - explicit TMat33(const TVec3<U>& v); + explicit CONSTEXPR TMat33(const TVec3<U>& v); /** * construct from another matrix of the same size */ template <typename U> - explicit TMat33(const TMat33<U>& rhs); + explicit CONSTEXPR TMat33(const TMat33<U>& rhs); /** * construct from 3 column vectors. @@ -209,7 +214,7 @@ public: * \f$ */ template <typename A, typename B, typename C> - TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2); + CONSTEXPR TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2); /** construct from 9 elements in column-major form. * @@ -227,7 +232,8 @@ public: typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> - TMat33(A m00, B m01, C m02, + CONSTEXPR TMat33( + A m00, B m01, C m02, D m10, E m11, F m12, G m20, H m21, I m22); @@ -235,19 +241,19 @@ public: * construct from a quaternion */ template <typename U> - explicit TMat33(const TQuaternion<U>& q); + explicit CONSTEXPR TMat33(const TQuaternion<U>& q); /** * construct from a C array in column major form. */ template <typename U> - explicit TMat33(U const* rawArray); + explicit CONSTEXPR TMat33(U const* rawArray); /** * orthogonalize only works on matrices of size 3x3 */ friend inline - TMat33 orthogonalize(const TMat33& m) { + CONSTEXPR TMat33 orthogonalize(const TMat33& m) { TMat33 ret(TMat33::NO_INIT); ret[0] = normalize(m[0]); ret[2] = normalize(cross(ret[0], m[1])); @@ -264,7 +270,7 @@ public: // operations. template <typename T> -TMat33<T>::TMat33() { +CONSTEXPR TMat33<T>::TMat33() { m_value[0] = col_type(1, 0, 0); m_value[1] = col_type(0, 1, 0); m_value[2] = col_type(0, 0, 1); @@ -272,7 +278,7 @@ TMat33<T>::TMat33() { template <typename T> template <typename U> -TMat33<T>::TMat33(U v) { +CONSTEXPR TMat33<T>::TMat33(U v) { m_value[0] = col_type(v, 0, 0); m_value[1] = col_type(0, v, 0); m_value[2] = col_type(0, 0, v); @@ -280,7 +286,7 @@ TMat33<T>::TMat33(U v) { template<typename T> template<typename U> -TMat33<T>::TMat33(const TVec3<U>& v) { +CONSTEXPR TMat33<T>::TMat33(const TVec3<U>& v) { m_value[0] = col_type(v.x, 0, 0); m_value[1] = col_type(0, v.y, 0); m_value[2] = col_type(0, 0, v.z); @@ -294,9 +300,10 @@ template < typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> -TMat33<T>::TMat33(A m00, B m01, C m02, - D m10, E m11, F m12, - G m20, H m21, I m22) { +CONSTEXPR TMat33<T>::TMat33( + A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) { m_value[0] = col_type(m00, m01, m02); m_value[1] = col_type(m10, m11, m12); m_value[2] = col_type(m20, m21, m22); @@ -304,7 +311,7 @@ TMat33<T>::TMat33(A m00, B m01, C m02, template <typename T> template <typename U> -TMat33<T>::TMat33(const TMat33<U>& rhs) { +CONSTEXPR TMat33<T>::TMat33(const TMat33<U>& rhs) { for (size_t col = 0; col < NUM_COLS; ++col) { m_value[col] = col_type(rhs[col]); } @@ -313,7 +320,7 @@ TMat33<T>::TMat33(const TMat33<U>& rhs) { // Construct from 3 column vectors. template <typename T> template <typename A, typename B, typename C> -TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) { +CONSTEXPR TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) { m_value[0] = v0; m_value[1] = v1; m_value[2] = v2; @@ -322,7 +329,7 @@ TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) { // Construct from raw array, in column-major form. template <typename T> template <typename U> -TMat33<T>::TMat33(U const* rawArray) { +CONSTEXPR TMat33<T>::TMat33(U const* rawArray) { for (size_t col = 0; col < NUM_COLS; ++col) { for (size_t row = 0; row < NUM_ROWS; ++row) { m_value[col][row] = *rawArray++; @@ -332,7 +339,7 @@ TMat33<T>::TMat33(U const* rawArray) { template <typename T> template <typename U> -TMat33<T>::TMat33(const TQuaternion<U>& q) { +CONSTEXPR TMat33<T>::TMat33(const TQuaternion<U>& q) { const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; const U s = n > 0 ? 2/n : 0; const U x = s*q.x; @@ -366,7 +373,7 @@ TMat33<T>::TMat33(const TQuaternion<U>& q) { // matrix * column-vector, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U>& rhs) { +CONSTEXPR typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U>& rhs) { // Result is initialized to zero. typename TMat33<U>::col_type result; for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) { @@ -377,7 +384,7 @@ typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U // row-vector * matrix, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat33<U>::row_type PURE operator *(const TVec3<U>& lhs, const TMat33<T>& rhs) { +CONSTEXPR typename TMat33<U>::row_type PURE operator *(const TVec3<U>& lhs, const TMat33<T>& rhs) { typename TMat33<U>::row_type result(TMat33<U>::row_type::NO_INIT); for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) { result[col] = dot(lhs, rhs[col]); @@ -401,7 +408,7 @@ operator*(U lhs, const TMat33<T>& rhs) { //------------------------------------------------------------------------------ template <typename T> -TMat33<T> orthogonalize(const TMat33<T>& m) { +CONSTEXPR TMat33<T> orthogonalize(const TMat33<T>& m) { TMat33<T> ret(TMat33<T>::NO_INIT); ret[0] = normalize(m[0]); ret[2] = normalize(cross(ret[0], m[1])); @@ -415,7 +422,7 @@ TMat33<T> orthogonalize(const TMat33<T>& m) { * BASE<T>::col_type is not accessible from there (???) */ template<typename T> -typename TMat33<T>::col_type PURE diag(const TMat33<T>& m) { +CONSTEXPR typename TMat33<T>::col_type PURE diag(const TMat33<T>& m) { return matrix::diag(m); } @@ -431,5 +438,6 @@ typedef details::TMat33<float> mat3f; } // namespace android #undef PURE +#undef CONSTEXPR #endif // UI_MAT3_H_ diff --git a/include/ui/mat4.h b/include/ui/mat4.h index a607023e16..f63d40aa6a 100644 --- a/include/ui/mat4.h +++ b/include/ui/mat4.h @@ -29,6 +29,12 @@ #define PURE __attribute__((pure)) +#if __cplusplus >= 201402L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + namespace android { // ------------------------------------------------------------------------------------- namespace details { @@ -141,8 +147,7 @@ public: */ // leaves object uninitialized. use with caution. - explicit - constexpr TMat44(no_init) + explicit constexpr TMat44(no_init) : m_value{ col_type(col_type::NO_INIT), col_type(col_type::NO_INIT), col_type(col_type::NO_INIT), @@ -161,7 +166,7 @@ public: * \right) * \f$ */ - TMat44(); + CONSTEXPR TMat44(); /** initialize to Identity*scalar. * @@ -177,7 +182,7 @@ public: * \f$ */ template<typename U> - explicit TMat44(U v); + explicit CONSTEXPR TMat44(U v); /** sets the diagonal to a vector. * @@ -193,11 +198,11 @@ public: * \f$ */ template <typename U> - explicit TMat44(const TVec4<U>& v); + explicit CONSTEXPR TMat44(const TVec4<U>& v); // construct from another matrix of the same size template <typename U> - explicit TMat44(const TMat44<U>& rhs); + explicit CONSTEXPR TMat44(const TMat44<U>& rhs); /** construct from 4 column vectors. * @@ -210,7 +215,7 @@ public: * \f$ */ template <typename A, typename B, typename C, typename D> - TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3); + CONSTEXPR TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3); /** construct from 16 elements in column-major form. * @@ -230,66 +235,67 @@ public: typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> - TMat44(A m00, B m01, C m02, D m03, - E m10, F m11, G m12, H m13, - I m20, J m21, K m22, L m23, - M m30, N m31, O m32, P m33); + CONSTEXPR TMat44( + A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33); /** * construct from a quaternion */ template <typename U> - explicit TMat44(const TQuaternion<U>& q); + explicit CONSTEXPR TMat44(const TQuaternion<U>& q); /** * construct from a C array in column major form. */ template <typename U> - explicit TMat44(U const* rawArray); + explicit CONSTEXPR TMat44(U const* rawArray); /** * construct from a 3x3 matrix */ template <typename U> - explicit TMat44(const TMat33<U>& matrix); + explicit CONSTEXPR TMat44(const TMat33<U>& matrix); /** * construct from a 3x3 matrix and 3d translation */ template <typename U, typename V> - TMat44(const TMat33<U>& matrix, const TVec3<V>& translation); + CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec3<V>& translation); /** * construct from a 3x3 matrix and 4d last column. */ template <typename U, typename V> - TMat44(const TMat33<U>& matrix, const TVec4<V>& column3); + CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec4<V>& column3); /* * helpers */ - static TMat44 ortho(T left, T right, T bottom, T top, T near, T far); + static CONSTEXPR TMat44 ortho(T left, T right, T bottom, T top, T near, T far); - static TMat44 frustum(T left, T right, T bottom, T top, T near, T far); + static CONSTEXPR TMat44 frustum(T left, T right, T bottom, T top, T near, T far); enum class Fov { HORIZONTAL, VERTICAL }; - static TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL); + static CONSTEXPR TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL); template <typename A, typename B, typename C> - static TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up); + static CONSTEXPR TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up); template <typename A> - static TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) { + static CONSTEXPR TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) { TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 }; return r.xyz / r.w; } template <typename A> - static TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) { + static CONSTEXPR TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) { vertice = projectionMatrix * vertice; return { vertice.xyz / vertice.w, 1 }; } @@ -310,7 +316,7 @@ public: // operations. template <typename T> -TMat44<T>::TMat44() { +CONSTEXPR TMat44<T>::TMat44() { m_value[0] = col_type(1, 0, 0, 0); m_value[1] = col_type(0, 1, 0, 0); m_value[2] = col_type(0, 0, 1, 0); @@ -319,7 +325,7 @@ TMat44<T>::TMat44() { template <typename T> template <typename U> -TMat44<T>::TMat44(U v) { +CONSTEXPR TMat44<T>::TMat44(U v) { m_value[0] = col_type(v, 0, 0, 0); m_value[1] = col_type(0, v, 0, 0); m_value[2] = col_type(0, 0, v, 0); @@ -328,7 +334,7 @@ TMat44<T>::TMat44(U v) { template<typename T> template<typename U> -TMat44<T>::TMat44(const TVec4<U>& v) { +CONSTEXPR TMat44<T>::TMat44(const TVec4<U>& v) { m_value[0] = col_type(v.x, 0, 0, 0); m_value[1] = col_type(0, v.y, 0, 0); m_value[2] = col_type(0, 0, v.z, 0); @@ -342,10 +348,11 @@ template < typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> -TMat44<T>::TMat44(A m00, B m01, C m02, D m03, - E m10, F m11, G m12, H m13, - I m20, J m21, K m22, L m23, - M m30, N m31, O m32, P m33) { +CONSTEXPR TMat44<T>::TMat44( + A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) { m_value[0] = col_type(m00, m01, m02, m03); m_value[1] = col_type(m10, m11, m12, m13); m_value[2] = col_type(m20, m21, m22, m23); @@ -354,7 +361,7 @@ TMat44<T>::TMat44(A m00, B m01, C m02, D m03, template <typename T> template <typename U> -TMat44<T>::TMat44(const TMat44<U>& rhs) { +CONSTEXPR TMat44<T>::TMat44(const TMat44<U>& rhs) { for (size_t col = 0; col < NUM_COLS; ++col) { m_value[col] = col_type(rhs[col]); } @@ -363,7 +370,9 @@ TMat44<T>::TMat44(const TMat44<U>& rhs) { // Construct from 4 column vectors. template <typename T> template <typename A, typename B, typename C, typename D> -TMat44<T>::TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3) { +CONSTEXPR TMat44<T>::TMat44( + const TVec4<A>& v0, const TVec4<B>& v1, + const TVec4<C>& v2, const TVec4<D>& v3) { m_value[0] = col_type(v0); m_value[1] = col_type(v1); m_value[2] = col_type(v2); @@ -373,7 +382,7 @@ TMat44<T>::TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, co // Construct from raw array, in column-major form. template <typename T> template <typename U> -TMat44<T>::TMat44(U const* rawArray) { +CONSTEXPR TMat44<T>::TMat44(U const* rawArray) { for (size_t col = 0; col < NUM_COLS; ++col) { for (size_t row = 0; row < NUM_ROWS; ++row) { m_value[col][row] = *rawArray++; @@ -383,7 +392,7 @@ TMat44<T>::TMat44(U const* rawArray) { template <typename T> template <typename U> -TMat44<T>::TMat44(const TQuaternion<U>& q) { +CONSTEXPR TMat44<T>::TMat44(const TQuaternion<U>& q) { const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; const U s = n > 0 ? 2/n : 0; const U x = s*q.x; @@ -406,7 +415,7 @@ TMat44<T>::TMat44(const TQuaternion<U>& q) { template <typename T> template <typename U> -TMat44<T>::TMat44(const TMat33<U>& m) { +CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m) { m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0); m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0); m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0); @@ -415,7 +424,7 @@ TMat44<T>::TMat44(const TMat33<U>& m) { template <typename T> template <typename U, typename V> -TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) { +CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) { m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0); m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0); m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0); @@ -424,7 +433,7 @@ TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) { template <typename T> template <typename U, typename V> -TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) { +CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) { m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0); // NOLINT m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0); // NOLINT m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0); // NOLINT @@ -436,7 +445,7 @@ TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) { // ---------------------------------------------------------------------------------------- template <typename T> -TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) { +CONSTEXPR TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) { TMat44<T> m; m[0][0] = 2 / (right - left); m[1][1] = 2 / (top - bottom); @@ -448,7 +457,7 @@ TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) { } template <typename T> -TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) { +CONSTEXPR TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) { TMat44<T> m; m[0][0] = (2 * near) / (right - left); m[1][1] = (2 * near) / (top - bottom); @@ -462,7 +471,7 @@ TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) { } template <typename T> -TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) { +CONSTEXPR TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) { T h; T w; @@ -483,7 +492,7 @@ TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov dir */ template <typename T> template <typename A, typename B, typename C> -TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) { +CONSTEXPR TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) { TVec3<T> z_axis(normalize(center - eye)); TVec3<T> norm_up(normalize(up)); if (std::abs(dot(z_axis, norm_up)) > 0.999) { @@ -513,7 +522,7 @@ TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const T // matrix * column-vector, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) { +CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) { // Result is initialized to zero. typename TMat44<T>::col_type result; for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) { @@ -524,14 +533,14 @@ typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U // mat44 * vec3, result is vec3( mat44 * {vec3, 1} ) template <typename T, typename U> -typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) { +CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) { return lhs * TVec4<U>{ rhs, 1 }; } // row-vector * matrix, result is a vector of the same type than the input vector template <typename T, typename U> -typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) { +CONSTEXPR typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) { typename TMat44<U>::row_type result(TMat44<U>::row_type::NO_INIT); for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) { result[col] = dot(lhs, rhs[col]); @@ -575,5 +584,6 @@ typedef details::TMat44<float> mat4f; } // namespace android #undef PURE +#undef CONSTEXPR #endif // UI_MAT4_H_ diff --git a/include/ui/quat.h b/include/ui/quat.h index 8c89cd7eb9..5b8cd8b9fe 100644 --- a/include/ui/quat.h +++ b/include/ui/quat.h @@ -29,6 +29,10 @@ #define PURE __attribute__((pure)) #endif +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +#pragma clang diagnostic ignored "-Wnested-anon-types" + namespace android { // ------------------------------------------------------------------------------------- @@ -142,48 +146,50 @@ typedef details::TQuaternion<float> quatf; typedef details::TQuaternion<half> quath; constexpr inline quat operator"" _i(long double v) { - return quat(0, v, 0, 0); + return quat(0, static_cast<float>(v), 0, 0); } constexpr inline quat operator"" _j(long double v) { - return quat(0, 0, v, 0); + return quat(0, 0, static_cast<float>(v), 0); } constexpr inline quat operator"" _k(long double v) { - return quat(0, 0, 0, v); + return quat(0, 0, 0, static_cast<float>(v)); } constexpr inline quat operator"" _i(unsigned long long v) { // NOLINT - return quat(0, v, 0, 0); + return quat(0, static_cast<float>(v), 0, 0); } constexpr inline quat operator"" _j(unsigned long long v) { // NOLINT - return quat(0, 0, v, 0); + return quat(0, 0, static_cast<float>(v), 0); } constexpr inline quat operator"" _k(unsigned long long v) { // NOLINT - return quat(0, 0, 0, v); + return quat(0, 0, 0, static_cast<float>(v)); } constexpr inline quatd operator"" _id(long double v) { - return quatd(0, v, 0, 0); + return quatd(0, static_cast<double>(v), 0, 0); } constexpr inline quatd operator"" _jd(long double v) { - return quatd(0, 0, v, 0); + return quatd(0, 0, static_cast<double>(v), 0); } constexpr inline quatd operator"" _kd(long double v) { - return quatd(0, 0, 0, v); + return quatd(0, 0, 0, static_cast<double>(v)); } constexpr inline quatd operator"" _id(unsigned long long v) { // NOLINT - return quatd(0, v, 0, 0); + return quatd(0, static_cast<double>(v), 0, 0); } constexpr inline quatd operator"" _jd(unsigned long long v) { // NOLINT - return quatd(0, 0, v, 0); + return quatd(0, 0, static_cast<double>(v), 0); } constexpr inline quatd operator"" _kd(unsigned long long v) { // NOLINT - return quatd(0, 0, 0, v); + return quatd(0, 0, 0, static_cast<double>(v)); } // ---------------------------------------------------------------------------------------- } // namespace android +#pragma clang diagnostic pop + #undef PURE #endif // UI_QUAT_H_ diff --git a/include/ui/scalar.h b/include/ui/scalar.h index c938d5cda2..5f8329e091 100644 --- a/include/ui/scalar.h +++ b/include/ui/scalar.h @@ -42,126 +42,6 @@ static constexpr T lerp(T x, T y, T a) noexcept { return mix(x, y, a); } -namespace details { - static int asInt(float x) { - return *reinterpret_cast<int*>(&x); - } - - static float asFloat(int x) { - return *reinterpret_cast<float*>(&x); - } - - static constexpr float inversesqrtNewtonRaphson(float x, float inverseSqrtX) { - return inverseSqrtX * (-x * 0.5f * (inverseSqrtX * inverseSqrtX) + 1.5f); - } - - static constexpr float rcpNewtonRaphson(float x, float rcpX) { - return rcpX * (-rcpX * x + 2.0f); - } - - static const float inverseSqrtFast(float f, int c) { - int v = details::asInt(f); - v = c - (v >> 1); - return details::asFloat(v); - } - - static const float rcpFast(float f, int c) { - int v = details::asInt(f); - v = c - v; - return details::asFloat(v); - } -} // namespace details - -/** - * Approximates an inverse square root using a specified - * number of Newton-Raphson iterations. The number of iterations - * can be: - * - * - 0, with a precision of ~3.4% over the full range - * - 1, with a precision of ~0.2% over the full range - * - 2, with a precision of ~4e-4% over the full range - */ -template<int> -static float inversesqrtFast(float f) noexcept; - -template<> -float inversesqrtFast<0>(float f) noexcept { - return details::inverseSqrtFast(f, 0x5f3759df); -} - -template<> -float inversesqrtFast<1>(float f) noexcept { - float x = details::inverseSqrtFast(f, 0x5f375a86); - return details::inversesqrtNewtonRaphson(f, x); -} - -template<> -float inversesqrtFast<2>(float f) noexcept { - float x = details::inverseSqrtFast(f, 0x5f375a86); - x = details::inversesqrtNewtonRaphson(f, x); - x = details::inversesqrtNewtonRaphson(f, x); - return x; -} - -/** - * Approximates a square root using a specified number of - * Newton-Raphson iterations. The number of iterations can be: - * - * - 0, with a precision of ~0.7% over the full range - * - 1, with a precision of ~0.2% over the full range - * - 2, with a precision of ~4e-4% over the full range - */ -template<int> -static float sqrtFast(float f) noexcept; - -template<> -float sqrtFast<0>(float f) noexcept { - int v = details::asInt(f); - v = 0x1fbd1df5 + (v >> 1); - return details::asFloat(v); -} - -template<> -float sqrtFast<1>(float f) noexcept { - return f * inversesqrtFast<1>(f); -} - -template<> -float sqrtFast<2>(float f) noexcept { - return f * inversesqrtFast<2>(f); -} - -/** - * Approximates a reciprocal using a specified number - * of Newton-Raphson iterations. The number of iterations - * can be: - * - * - 0, with a precision of ~0.4% over the full range - * - 1, with a precision of ~0.02% over the full range - * - 2, with a precision of ~5e-5% over the full range - */ -template<int> -static float rcpFast(float f) noexcept; - -template<> -float rcpFast<0>(float f) noexcept { - return details::rcpFast(f, 0x7ef311c2); -} - -template<> -float rcpFast<1>(float f) noexcept { - float x = details::rcpFast(f, 0x7ef311c3); - return details::rcpNewtonRaphson(f, x); -} - -template<> -float rcpFast<2>(float f) noexcept { - float x = details::rcpFast(f, 0x7ef312ac); - x = details::rcpNewtonRaphson(f, x); - x = details::rcpNewtonRaphson(f, x); - return x; -} - } // namespace std #endif // UI_SCALAR_H diff --git a/include/ui/vec2.h b/include/ui/vec2.h index a88d026491..fdd2e202fa 100644 --- a/include/ui/vec2.h +++ b/include/ui/vec2.h @@ -24,6 +24,9 @@ #include <sys/types.h> #include <type_traits> +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +#pragma clang diagnostic ignored "-Wnested-anon-types" namespace android { // ------------------------------------------------------------------------------------- @@ -94,7 +97,7 @@ public: constexpr TVec2(const TVec2<A>& v) : x(v.x), y(v.y) { } // cross product works only on vectors of size 2 or 3 - template <typename RT> + template<typename RT> friend inline constexpr value_type cross(const TVec2& u, const TVec2<RT>& v) { return value_type(u.x*v.y - u.y*v.x); @@ -119,4 +122,6 @@ typedef details::TVec2<uint8_t> ubyte2; // ---------------------------------------------------------------------------------------- } // namespace android +#pragma clang diagnostic pop + #endif // UI_VEC2_H_ diff --git a/include/ui/vec3.h b/include/ui/vec3.h index 0254f5a2c6..f76b2ec0dd 100644 --- a/include/ui/vec3.h +++ b/include/ui/vec3.h @@ -22,6 +22,9 @@ #include <stdint.h> #include <sys/types.h> +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +#pragma clang diagnostic ignored "-Wnested-anon-types" namespace android { // ------------------------------------------------------------------------------------- @@ -125,4 +128,6 @@ typedef details::TVec3<uint8_t> ubyte3; // ---------------------------------------------------------------------------------------- } // namespace android +#pragma clang diagnostic pop + #endif // UI_VEC3_H_ diff --git a/include/ui/vec4.h b/include/ui/vec4.h index 1281aa40cb..e13ad96913 100644 --- a/include/ui/vec4.h +++ b/include/ui/vec4.h @@ -22,6 +22,9 @@ #include <stdint.h> #include <sys/types.h> +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +#pragma clang diagnostic ignored "-Wnested-anon-types" namespace android { // ------------------------------------------------------------------------------------- @@ -122,4 +125,6 @@ typedef details::TVec4<uint8_t> ubyte4; // ---------------------------------------------------------------------------------------- } // namespace android +#pragma clang diagnostic pop + #endif // UI_VEC4_H_ diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 0d1f604937..087e877263 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -41,6 +41,7 @@ cc_library_shared { }, srcs: [ + "ColorSpace.cpp", "Fence.cpp", "FrameStats.cpp", "Gralloc1.cpp", diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp new file mode 100644 index 0000000000..081aca9d55 --- /dev/null +++ b/libs/ui/ColorSpace.cpp @@ -0,0 +1,241 @@ +/* + * 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 <ui/ColorSpace.h> + +using namespace std::placeholders; + +namespace android { + +ColorSpace::ColorSpace( + const std::string& name, + const mat3& rgbToXYZ, + transfer_function OETF, + transfer_function EOTF, + clamping_function clamper) noexcept + : mName(name) + , mRGBtoXYZ(rgbToXYZ) + , mXYZtoRGB(inverse(rgbToXYZ)) + , mOETF(std::move(OETF)) + , mEOTF(std::move(EOTF)) + , mClamper(std::move(clamper)) { + + float3 r(rgbToXYZ * float3{1, 0, 0}); + float3 g(rgbToXYZ * float3{0, 1, 0}); + float3 b(rgbToXYZ * float3{0, 0, 1}); + + mPrimaries[0] = r.xy / dot(r, float3{1}); + mPrimaries[1] = g.xy / dot(g, float3{1}); + mPrimaries[2] = b.xy / dot(b, float3{1}); + + float3 w(rgbToXYZ * float3{1}); + mWhitePoint = w.xy / dot(w, float3{1}); +} + +ColorSpace::ColorSpace( + const std::string& name, + const std::array<float2, 3>& primaries, + const float2& whitePoint, + transfer_function OETF, + transfer_function EOTF, + clamping_function clamper) noexcept + : mName(name) + , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint)) + , mXYZtoRGB(inverse(mRGBtoXYZ)) + , mOETF(std::move(OETF)) + , mEOTF(std::move(EOTF)) + , mClamper(std::move(clamper)) + , mPrimaries(primaries) + , mWhitePoint(whitePoint) { +} + +constexpr mat3 ColorSpace::computeXYZMatrix( + const std::array<float2, 3>& primaries, const float2& whitePoint) { + const float2& R = primaries[0]; + const float2& G = primaries[1]; + const float2& B = primaries[2]; + const float2& W = whitePoint; + + float oneRxRy = (1 - R.x) / R.y; + float oneGxGy = (1 - G.x) / G.y; + float oneBxBy = (1 - B.x) / B.y; + float oneWxWy = (1 - W.x) / W.y; + + float RxRy = R.x / R.y; + float GxGy = G.x / G.y; + float BxBy = B.x / B.y; + float WxWy = W.x / W.y; + + float BY = + ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) / + ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy)); + float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy); + float RY = 1 - GY - BY; + + float RYRy = RY / R.y; + float GYGy = GY / G.y; + float BYBy = BY / B.y; + + return { + float3{RYRy * R.x, RY, RYRy * (1 - R.x - R.y)}, + float3{GYGy * G.x, GY, GYGy * (1 - G.x - G.y)}, + float3{BYBy * B.x, BY, BYBy * (1 - B.x - B.y)} + }; +} + +static constexpr float rcpResponse(float x, float g,float a, float b, float c, float d) { + return x >= d * c ? std::pow(x / a, 1.0f / g) - b / a : x / c; +} + +static constexpr float response(float x, float g, float a, float b, float c, float d) { + return x >= d ? std::pow(a * x + b, g) : c * x; +} + +static float absRcpResponse(float x, float g,float a, float b, float c, float d) { + return std::copysign(rcpResponse(std::abs(x), g, a, b, c, d), x); +} + +static float absResponse(float x, float g, float a, float b, float c, float d) { + return std::copysign(response(std::abs(x), g, a, b, c, d), x); +} + +const ColorSpace ColorSpace::sRGB() { + return { + "sRGB IEC61966-2.1", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f), + std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f) + }; +} + +const ColorSpace ColorSpace::linearSRGB() { + return { + "sRGB IEC61966-2.1 (Linear)", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f} + }; +} + +const ColorSpace ColorSpace::extendedSRGB() { + return { + "scRGB-nl IEC 61966-2-2:2003", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + std::bind(absRcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f), + std::bind(absResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f), + [](float x){return x;} + }; +} + +const ColorSpace ColorSpace::linearExtendedSRGB() { + return { + "scRGB IEC 61966-2-2:2003", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + linearReponse, + linearReponse, + [](float x){return x;} + }; +} + +const ColorSpace ColorSpace::NTSC() { + return { + "NTSC (1953)", + {{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}}, + {0.310f, 0.316f}, + std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f), + std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f) + }; +} + +const ColorSpace ColorSpace::BT709() { + return { + "Rec. ITU-R BT.709-5", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f), + std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f) + }; +} + +const ColorSpace ColorSpace::BT2020() { + return { + "Rec. ITU-R BT.2020-1", + {{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}}, + {0.3127f, 0.3290f}, + std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f), + std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f) + }; +} + +const ColorSpace ColorSpace::AdobeRGB() { + return { + "Adobe RGB (1998)", + {{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}}, + {0.3127f, 0.3290f}, + std::bind(saturate<float>, std::bind(powf, _1, 1.0f / 2.2f)), + std::bind(saturate<float>, std::bind(powf, _1, 2.2f)) + }; +} + +const ColorSpace ColorSpace::ProPhotoRGB() { + return { + "ROMM RGB ISO 22028-2:2013", + {{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}}, + {0.3457f, 0.3585f}, + std::bind(rcpResponse, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f), + std::bind(response, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f) + }; +} + +const ColorSpace ColorSpace::DisplayP3() { + return { + "Display P3", + {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f), + std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f) + }; +} + +const ColorSpace ColorSpace::DCIP3() { + return { + "SMPTE RP 431-2-2007 DCI (P3)", + {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f}, + std::bind(saturate<float>, std::bind(powf, _1, 1.0f / 2.6f)), + std::bind(saturate<float>, std::bind(powf, _1, 2.6f)) + }; +} + +const ColorSpace ColorSpace::ACES() { + return { + "SMPTE ST 2065-1:2012 ACES", + {{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}}, + {0.32168f, 0.33767f} + }; +} + +const ColorSpace ColorSpace::ACEScg() { + return { + "Academy S-2014-004 ACEScg", + {{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}}, + {0.32168f, 0.33767f} + }; +} + +}; // namespace android diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 9594466ef1..c4f34d5fdc 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -39,3 +39,9 @@ cc_test { name: "quat_test", srcs: ["quat_test.cpp"], } + +cc_test { + name: "colorspace_test", + shared_libs: ["libui"], + srcs: ["colorspace_test.cpp"], +} diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp new file mode 100644 index 0000000000..5c127adf2e --- /dev/null +++ b/libs/ui/tests/colorspace_test.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2013 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. + */ + +#define LOG_TAG "ColorSpaceTest" + +#include <math.h> +#include <stdlib.h> + +#include <ui/ColorSpace.h> + +#include <gtest/gtest.h> + +namespace android { + +class ColorSpaceTest : public testing::Test { +protected: +}; + +TEST_F(ColorSpaceTest, XYZ) { + mat3 sRGBToXYZ(transpose(mat3{ + 0.412391f, 0.357584f, 0.180481f, + 0.212639f, 0.715169f, 0.072192f, + 0.019331f, 0.119195f, 0.950532f + })); + + mat3 XYZtoSRGB(inverse(sRGBToXYZ)); + + ColorSpace sRGB("sRGB", sRGBToXYZ); + + EXPECT_EQ(sRGBToXYZ, sRGB.getRGBtoXYZ()); + EXPECT_EQ(XYZtoSRGB, sRGB.getXYZtoRGB()); +} + +TEST_F(ColorSpaceTest, XYZPrimaries) { + mat3 sRGBToXYZ(transpose(mat3{ + 0.412391f, 0.357584f, 0.180481f, + 0.212639f, 0.715169f, 0.072192f, + 0.019331f, 0.119195f, 0.950532f + })); + + ColorSpace sRGB("sRGB", sRGBToXYZ); + + EXPECT_NEAR(0.640f, sRGB.getPrimaries()[0].x, 1e-5f); + EXPECT_NEAR(0.330f, sRGB.getPrimaries()[0].y, 1e-5f); + + EXPECT_NEAR(0.300f, sRGB.getPrimaries()[1].x, 1e-5f); + EXPECT_NEAR(0.600f, sRGB.getPrimaries()[1].y, 1e-5f); + + EXPECT_NEAR(0.150f, sRGB.getPrimaries()[2].x, 1e-5f); + EXPECT_NEAR(0.060f, sRGB.getPrimaries()[2].y, 1e-5f); +} + +TEST_F(ColorSpaceTest, XYZWhitePoint) { + mat3 sRGBToXYZ(transpose(mat3{ + 0.412391f, 0.357584f, 0.180481f, + 0.212639f, 0.715169f, 0.072192f, + 0.019331f, 0.119195f, 0.950532f + })); + + ColorSpace sRGB("sRGB", sRGBToXYZ); + + EXPECT_NEAR(0.3127f, sRGB.getWhitePoint().x, 1e-5f); + EXPECT_NEAR(0.3290f, sRGB.getWhitePoint().y, 1e-5f); +} + +TEST_F(ColorSpaceTest, XYZFromPrimaries) { + mat3 sRGBToXYZ(transpose(mat3{ + 0.412391f, 0.357584f, 0.180481f, + 0.212639f, 0.715169f, 0.072192f, + 0.019331f, 0.119195f, 0.950532f + })); + + ColorSpace sRGB1("sRGB", sRGBToXYZ); + ColorSpace sRGB2( + "sRGB", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f} + ); + + for (size_t i = 0; i < 3; i++) { + for (size_t j= 0; j < 3; j++) { + ASSERT_NEAR(sRGB1.getRGBtoXYZ()[i][j], sRGB2.getRGBtoXYZ()[i][j], 1e-5f); + } + } + + for (size_t i = 0; i < 3; i++) { + for (size_t j= 0; j < 3; j++) { + ASSERT_NEAR(sRGB2.getXYZtoRGB()[i][j], sRGB2.getXYZtoRGB()[i][j], 1e-5f); + } + } +} + +TEST_F(ColorSpaceTest, TransferFunctions) { + ColorSpace sRGB = ColorSpace::sRGB(); + + for (float v = 0.0f; v <= 0.5f; v += 1e-3f) { + ASSERT_TRUE(v >= sRGB.getEOTF()(v)); + ASSERT_TRUE(v <= sRGB.getOETF()(v)); + } + + float previousEOTF = std::numeric_limits<float>::lowest(); + float previousOETF = std::numeric_limits<float>::lowest(); + for (float v = 0.0f; v <= 1.0f; v += 1e-3f) { + ASSERT_TRUE(previousEOTF < sRGB.getEOTF()(v)); + previousEOTF = sRGB.getEOTF()(v); + ASSERT_TRUE(previousOETF < sRGB.getOETF()(v)); + previousOETF = sRGB.getOETF()(v); + } + + ColorSpace sRGB2( + "sRGB", + {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}}, + {0.3127f, 0.3290f} + // linear transfer functions + ); + for (float v = 0.0f; v <= 1.0f; v += 1e-3f) { + ASSERT_EQ(v, sRGB2.getEOTF()(v)); + ASSERT_EQ(v, sRGB2.getOETF()(v)); + } +} + +TEST_F(ColorSpaceTest, Clamping) { + // Pick a color outside of sRGB + float3 c(ColorSpace::DCIP3().rgbToXYZ(float3{0, 1, 0})); + + // The color will be clamped + float3 sRGB(ColorSpace::sRGB().xyzToRGB(c)); + EXPECT_TRUE(sRGB > float3{0.0} && sRGB < float3{1.0}); + + // The color will not be clamped + float3 extendedSRGB(ColorSpace::linearExtendedSRGB().xyzToRGB(c)); + EXPECT_TRUE(extendedSRGB.g > 1.0f); +} + +}; // namespace android diff --git a/libs/ui/tests/half_test.cpp b/libs/ui/tests/half_test.cpp index 0ea9265f6e..b2a5e5cbc2 100644 --- a/libs/ui/tests/half_test.cpp +++ b/libs/ui/tests/half_test.cpp @@ -32,7 +32,7 @@ protected: TEST_F(HalfTest, Basics) { - EXPECT_EQ(2, sizeof(half)); + EXPECT_EQ(2UL, sizeof(half)); // test +/- zero EXPECT_EQ(0x0000, half( 0.0f).getBits()); |