diff options
-rw-r--r-- | api/current.txt | 36 | ||||
-rw-r--r-- | api/system-current.txt | 36 | ||||
-rw-r--r-- | api/test-current.txt | 36 | ||||
-rwxr-xr-x | core/jni/android/graphics/Bitmap.cpp | 77 | ||||
-rw-r--r-- | core/jni/android/graphics/BitmapFactory.cpp | 7 | ||||
-rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 19 | ||||
-rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 2 | ||||
-rw-r--r-- | core/jni/android_view_GraphicBuffer.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_view_Surface.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 10 | ||||
-rw-r--r-- | core/jni/android_view_TextureView.cpp | 8 | ||||
-rw-r--r-- | docs/html/reference/images/graphics/colorspace_ucs.png | bin | 0 -> 291374 bytes | |||
-rw-r--r-- | graphics/java/android/graphics/Bitmap.java | 43 | ||||
-rw-r--r-- | graphics/java/android/graphics/ColorSpace.java | 214 | ||||
-rw-r--r-- | graphics/java/android/graphics/PixelFormat.java | 32 | ||||
-rw-r--r-- | libs/hwui/OpenGLReadback.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/Texture.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/hwui/Bitmap.cpp | 5 |
18 files changed, 412 insertions, 134 deletions
diff --git a/api/current.txt b/api/current.txt index cec2b9fc2457..89573ace6dac 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11769,6 +11769,8 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); @@ -11833,6 +11835,7 @@ package android.graphics { enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444; enum_constant public static final android.graphics.Bitmap.Config ARGB_8888; enum_constant public static final android.graphics.Bitmap.Config HARDWARE; + enum_constant public static final android.graphics.Bitmap.Config RGBA_F16; enum_constant public static final android.graphics.Bitmap.Config RGB_565; } @@ -12192,6 +12195,7 @@ package android.graphics { method public android.graphics.Bitmap render(); method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean); method public android.graphics.ColorSpace.Renderer size(int); + method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean); } public static class ColorSpace.Rgb extends android.graphics.ColorSpace { @@ -12727,7 +12731,9 @@ package android.graphics { field public static final deprecated int RGBA_4444 = 7; // 0x7 field public static final deprecated int RGBA_5551 = 6; // 0x6 field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_F16 = 22; // 0x16 field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGBX_F16 = 23; // 0x17 field public static final deprecated int RGB_332 = 11; // 0xb field public static final int RGB_565 = 4; // 0x4 field public static final int RGB_888 = 3; // 0x3 @@ -61421,31 +61427,31 @@ package java.util.concurrent { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>); ctor public CopyOnWriteArrayList(E[]); - method public synchronized boolean add(E); - method public synchronized void add(int, E); - method public synchronized boolean addAll(java.util.Collection<? extends E>); - method public synchronized boolean addAll(int, java.util.Collection<? extends E>); - method public synchronized int addAllAbsent(java.util.Collection<? extends E>); - method public synchronized boolean addIfAbsent(E); - method public synchronized void clear(); + method public boolean add(E); + method public void add(int, E); + method public boolean addAll(java.util.Collection<? extends E>); + method public boolean addAll(int, java.util.Collection<? extends E>); + method public int addAllAbsent(java.util.Collection<? extends E>); + method public boolean addIfAbsent(E); + method public void clear(); method public java.lang.Object clone(); method public boolean contains(java.lang.Object); method public boolean containsAll(java.util.Collection<?>); method public void forEach(java.util.function.Consumer<? super E>); method public E get(int); - method public int indexOf(E, int); method public int indexOf(java.lang.Object); + method public int indexOf(E, int); method public boolean isEmpty(); method public java.util.Iterator<E> iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator<E> listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator<E> listIterator(); - method public synchronized E remove(int); - method public synchronized boolean remove(java.lang.Object); - method public synchronized boolean removeAll(java.util.Collection<?>); - method public synchronized boolean retainAll(java.util.Collection<?>); - method public synchronized E set(int, E); + method public java.util.ListIterator<E> listIterator(int); + method public E remove(int); + method public boolean remove(java.lang.Object); + method public boolean removeAll(java.util.Collection<?>); + method public boolean retainAll(java.util.Collection<?>); + method public E set(int, E); method public int size(); method public java.util.List<E> subList(int, int); method public java.lang.Object[] toArray(); diff --git a/api/system-current.txt b/api/system-current.txt index b0236ea15fc2..7d8da95f0b37 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12262,6 +12262,8 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); @@ -12326,6 +12328,7 @@ package android.graphics { enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444; enum_constant public static final android.graphics.Bitmap.Config ARGB_8888; enum_constant public static final android.graphics.Bitmap.Config HARDWARE; + enum_constant public static final android.graphics.Bitmap.Config RGBA_F16; enum_constant public static final android.graphics.Bitmap.Config RGB_565; } @@ -12685,6 +12688,7 @@ package android.graphics { method public android.graphics.Bitmap render(); method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean); method public android.graphics.ColorSpace.Renderer size(int); + method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean); } public static class ColorSpace.Rgb extends android.graphics.ColorSpace { @@ -13220,7 +13224,9 @@ package android.graphics { field public static final deprecated int RGBA_4444 = 7; // 0x7 field public static final deprecated int RGBA_5551 = 6; // 0x6 field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_F16 = 22; // 0x16 field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGBX_F16 = 23; // 0x17 field public static final deprecated int RGB_332 = 11; // 0xb field public static final int RGB_565 = 4; // 0x4 field public static final int RGB_888 = 3; // 0x3 @@ -64923,31 +64929,31 @@ package java.util.concurrent { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>); ctor public CopyOnWriteArrayList(E[]); - method public synchronized boolean add(E); - method public synchronized void add(int, E); - method public synchronized boolean addAll(java.util.Collection<? extends E>); - method public synchronized boolean addAll(int, java.util.Collection<? extends E>); - method public synchronized int addAllAbsent(java.util.Collection<? extends E>); - method public synchronized boolean addIfAbsent(E); - method public synchronized void clear(); + method public boolean add(E); + method public void add(int, E); + method public boolean addAll(java.util.Collection<? extends E>); + method public boolean addAll(int, java.util.Collection<? extends E>); + method public int addAllAbsent(java.util.Collection<? extends E>); + method public boolean addIfAbsent(E); + method public void clear(); method public java.lang.Object clone(); method public boolean contains(java.lang.Object); method public boolean containsAll(java.util.Collection<?>); method public void forEach(java.util.function.Consumer<? super E>); method public E get(int); - method public int indexOf(E, int); method public int indexOf(java.lang.Object); + method public int indexOf(E, int); method public boolean isEmpty(); method public java.util.Iterator<E> iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator<E> listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator<E> listIterator(); - method public synchronized E remove(int); - method public synchronized boolean remove(java.lang.Object); - method public synchronized boolean removeAll(java.util.Collection<?>); - method public synchronized boolean retainAll(java.util.Collection<?>); - method public synchronized E set(int, E); + method public java.util.ListIterator<E> listIterator(int); + method public E remove(int); + method public boolean remove(java.lang.Object); + method public boolean removeAll(java.util.Collection<?>); + method public boolean retainAll(java.util.Collection<?>); + method public E set(int, E); method public int size(); method public java.util.List<E> subList(int, int); method public java.lang.Object[] toArray(); diff --git a/api/test-current.txt b/api/test-current.txt index c798b5e165cd..251a353d2832 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -11800,6 +11800,8 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); @@ -11864,6 +11866,7 @@ package android.graphics { enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444; enum_constant public static final android.graphics.Bitmap.Config ARGB_8888; enum_constant public static final android.graphics.Bitmap.Config HARDWARE; + enum_constant public static final android.graphics.Bitmap.Config RGBA_F16; enum_constant public static final android.graphics.Bitmap.Config RGB_565; } @@ -12223,6 +12226,7 @@ package android.graphics { method public android.graphics.Bitmap render(); method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean); method public android.graphics.ColorSpace.Renderer size(int); + method public android.graphics.ColorSpace.Renderer uniformChromaticityScale(boolean); } public static class ColorSpace.Rgb extends android.graphics.ColorSpace { @@ -12758,7 +12762,9 @@ package android.graphics { field public static final deprecated int RGBA_4444 = 7; // 0x7 field public static final deprecated int RGBA_5551 = 6; // 0x6 field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_F16 = 22; // 0x16 field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGBX_F16 = 23; // 0x17 field public static final deprecated int RGB_332 = 11; // 0xb field public static final int RGB_565 = 4; // 0x4 field public static final int RGB_888 = 3; // 0x3 @@ -61710,31 +61716,31 @@ package java.util.concurrent { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>); ctor public CopyOnWriteArrayList(E[]); - method public synchronized boolean add(E); - method public synchronized void add(int, E); - method public synchronized boolean addAll(java.util.Collection<? extends E>); - method public synchronized boolean addAll(int, java.util.Collection<? extends E>); - method public synchronized int addAllAbsent(java.util.Collection<? extends E>); - method public synchronized boolean addIfAbsent(E); - method public synchronized void clear(); + method public boolean add(E); + method public void add(int, E); + method public boolean addAll(java.util.Collection<? extends E>); + method public boolean addAll(int, java.util.Collection<? extends E>); + method public int addAllAbsent(java.util.Collection<? extends E>); + method public boolean addIfAbsent(E); + method public void clear(); method public java.lang.Object clone(); method public boolean contains(java.lang.Object); method public boolean containsAll(java.util.Collection<?>); method public void forEach(java.util.function.Consumer<? super E>); method public E get(int); - method public int indexOf(E, int); method public int indexOf(java.lang.Object); + method public int indexOf(E, int); method public boolean isEmpty(); method public java.util.Iterator<E> iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator<E> listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator<E> listIterator(); - method public synchronized E remove(int); - method public synchronized boolean remove(java.lang.Object); - method public synchronized boolean removeAll(java.util.Collection<?>); - method public synchronized boolean retainAll(java.util.Collection<?>); - method public synchronized E set(int, E); + method public java.util.ListIterator<E> listIterator(int); + method public E remove(int); + method public boolean remove(java.lang.Object); + method public boolean removeAll(java.util.Collection<?>); + method public boolean retainAll(java.util.Collection<?>); + method public E set(int, E); method public int size(); method public java.util.List<E> subList(int, int); method public java.lang.Object[] toArray(); diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 673cf863391c..b656bb08cba9 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -5,7 +5,11 @@ #include "SkPixelRef.h" #include "SkImageEncoder.h" #include "SkImageInfo.h" +#include "SkColor.h" #include "SkColorPriv.h" +#include "SkHalf.h" +#include "SkPM4f.h" +#include "SkPM4fPriv.h" #include "GraphicsJNI.h" #include "SkDither.h" #include "SkUnPreMultiply.h" @@ -232,6 +236,28 @@ using namespace android::bitmap; typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, int x, int y); +static void FromColor_F16(void* dst, const SkColor src[], int width, + int, int) { + uint64_t* d = (uint64_t*)dst; + + for (int i = 0; i < width; i++) { + *d++ = SkColor4f::FromColor(*src++).premul().toF16(); + } +} + +static void FromColor_F16_Raw(void* dst, const SkColor src[], int width, + int, int) { + uint64_t* d = (uint64_t*)dst; + + for (int i = 0; i < width; i++) { + const float* color = SkColor4f::FromColor(*src++).vec(); + uint16_t* scratch = reinterpret_cast<uint16_t*>(d++); + for (int i = 0; i < 4; ++i) { + scratch[i] = SkFloatToHalf(color[i]); + } + } +} + static void FromColor_D32(void* dst, const SkColor src[], int width, int, int) { SkPMColor* d = (SkPMColor*)dst; @@ -321,6 +347,8 @@ static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) { return FromColor_D565; case kAlpha_8_SkColorType: return FromColor_DA8; + case kRGBA_F16_SkColorType: + return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw; default: break; } @@ -351,8 +379,7 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int dstBitmap.notifyPixelsChanged(); - env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), - JNI_ABORT); + env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT); return true; } @@ -361,6 +388,24 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, SkColorTable*); +static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + uint64_t* s = (uint64_t*)src; + do { + *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor(); + } while (--width != 0); +} + +static void ToColor_F16_Raw(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + uint64_t* s = (uint64_t*)src; + do { + *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++))); + } while (--width != 0); +} + static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, SkColorTable*) { SkASSERT(width > 0); @@ -520,6 +565,17 @@ static ToColorProc ChooseToColorProc(const SkBitmap& src) { } case kAlpha_8_SkColorType: return ToColor_SA8; + case kRGBA_F16_SkColorType: + switch (src.alphaType()) { + case kOpaque_SkAlphaType: + return ToColor_F16_Raw; + case kPremul_SkAlphaType: + return ToColor_F16_Alpha; + case kUnpremul_SkAlphaType: + return ToColor_F16_Raw; + default: + return NULL; + } default: break; } @@ -554,7 +610,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, SkBitmap bitmap; bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, - GraphicsJNI::defaultColorSpace())); + GraphicsJNI::colorSpaceForType(colorType))); sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL); if (!nativeBitmap) { @@ -562,8 +618,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, } if (jColors != NULL) { - GraphicsJNI::SetPixels(env, jColors, offset, stride, - 0, 0, width, height, bitmap); + GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap); } return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); @@ -790,6 +845,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { const int density = p->readInt32(); if (kN32_SkColorType != colorType && + kRGBA_F16_SkColorType != colorType && kRGB_565_SkColorType != colorType && kARGB_4444_SkColorType != colorType && kIndex_8_SkColorType != colorType && @@ -800,8 +856,15 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { std::unique_ptr<SkBitmap> bitmap(new SkBitmap); - if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, - isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) { + sk_sp<SkColorSpace> colorSpace; + if (kRGBA_F16_SkColorType == colorType) { + colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); + } else { + colorSpace = isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr; + } + + if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace), + rowBytes)) { return NULL; } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 18ed0ed72190..69c705494932 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -283,8 +283,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // Create the codec. NinePatchPeeker peeker; - std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), - &peeker)); + std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream( + streamDeleter.release(), &peeker)); if (!codec.get()) { return nullObjectReturn("SkAndroidCodec::NewFromStream returned null"); } @@ -399,7 +399,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // We always decode to sRGB, but only mark the bitmap with a color space if linear // blending is enabled. - SkImageInfo bitmapInfo = decodeInfo.makeColorSpace(GraphicsJNI::defaultColorSpace()); + SkImageInfo bitmapInfo = decodeInfo.makeColorSpace( + GraphicsJNI::colorSpaceForType(decodeColorType)); if (decodeColorType == kGray_8_SkColorType) { // The legacy implementation of BitmapFactory used kAlpha8 for // grayscale images (before kGray8 existed). While the codec diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index d8984d336746..6f97c600a1cc 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -297,13 +297,16 @@ enum LegacyBitmapConfig { kRGB_565_LegacyBitmapConfig = 3, kARGB_4444_LegacyBitmapConfig = 4, kARGB_8888_LegacyBitmapConfig = 5, - kHardware_LegacyBitmapConfig = 6, + kRGBA_16F_LegacyBitmapConfig = 6, + kHardware_LegacyBitmapConfig = 7, kLastEnum_LegacyBitmapConfig = kHardware_LegacyBitmapConfig }; jint GraphicsJNI::colorTypeToLegacyBitmapConfig(SkColorType colorType) { switch (colorType) { + case kRGBA_F16_SkColorType: + return kRGBA_16F_LegacyBitmapConfig; case kN32_SkColorType: return kARGB_8888_LegacyBitmapConfig; case kARGB_4444_SkColorType: @@ -329,6 +332,7 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { kRGB_565_SkColorType, kARGB_4444_SkColorType, kN32_SkColorType, + kRGBA_F16_SkColorType, kN32_SkColorType }; @@ -458,6 +462,19 @@ sk_sp<SkColorSpace> GraphicsJNI::defaultColorSpace() { #endif } +sk_sp<SkColorSpace> GraphicsJNI::linearColorSpace() { + return SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); +} + +sk_sp<SkColorSpace> GraphicsJNI::colorSpaceForType(SkColorType type) { + switch (type) { + case kRGBA_F16_SkColorType: + return linearColorSpace(); + default: + return defaultColorSpace(); + } +} + /////////////////////////////////////////////////////////////////////////////// bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 03dc1fbe82fa..508c9ffd0f20 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -95,6 +95,8 @@ public: const SkBitmap& dstBitmap); static sk_sp<SkColorSpace> defaultColorSpace(); + static sk_sp<SkColorSpace> linearColorSpace(); + static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type); }; class HeapAllocator : public SkBRDAllocator { diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index b6b524597896..bb69e27933b2 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -142,6 +142,10 @@ static inline SkColorType convertPixelFormat(int32_t format) { return kN32_SkColorType; case PIXEL_FORMAT_RGBX_8888: return kN32_SkColorType; + case PIXEL_FORMAT_RGBA_FP16: + return kRGBA_F16_SkColorType; + case PIXEL_FORMAT_RGBX_FP16: + return kRGBA_F16_SkColorType; case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; default: diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 92693b710424..a5b7671fa1ac 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -168,6 +168,8 @@ PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat( switch(format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_FP16: + case HAL_PIXEL_FORMAT_RGBX_FP16: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_Y8: @@ -283,6 +285,8 @@ static inline SkColorType convertPixelFormat(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBX_8888: return kN32_SkColorType; case PIXEL_FORMAT_RGBA_8888: return kN32_SkColorType; + case PIXEL_FORMAT_RGBX_FP16: return kRGBA_F16_SkColorType; + case PIXEL_FORMAT_RGBA_FP16: return kRGBA_F16_SkColorType; case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; default: return kUnknown_SkColorType; } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5b8818171b6f..62c3d04f117b 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -164,6 +164,16 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, alphaType = kPremul_SkAlphaType; break; } + case PIXEL_FORMAT_RGBX_FP16: { + colorType = kRGBA_F16_SkColorType; + alphaType = kOpaque_SkAlphaType; + break; + } + case PIXEL_FORMAT_RGBA_FP16: { + colorType = kRGBA_F16_SkColorType; + alphaType = kPremul_SkAlphaType; + break; + } case PIXEL_FORMAT_RGB_565: { colorType = kRGB_565_SkColorType; alphaType = kOpaque_SkAlphaType; diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index 3c8db7fd3c3d..d3c020215485 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -83,6 +83,14 @@ static inline SkImageInfo convertPixelFormat(const ANativeWindow_Buffer& buffer) colorType = kN32_SkColorType; alphaType = kOpaque_SkAlphaType; break; + case WINDOW_FORMAT_RGBA_FP16: + colorType = kRGBA_F16_SkColorType; + alphaType = kPremul_SkAlphaType; + break; + case WINDOW_FORMAT_RGBX_FP16: + colorType = kRGBA_F16_SkColorType; + alphaType = kOpaque_SkAlphaType; + break; case WINDOW_FORMAT_RGB_565: colorType = kRGB_565_SkColorType; alphaType = kOpaque_SkAlphaType; diff --git a/docs/html/reference/images/graphics/colorspace_ucs.png b/docs/html/reference/images/graphics/colorspace_ucs.png Binary files differnew file mode 100644 index 000000000000..3e0f0c6f0cc4 --- /dev/null +++ b/docs/html/reference/images/graphics/colorspace_ucs.png diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index cd75fe95121a..a041a28010e2 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -140,7 +140,7 @@ public final class Bitmap implements Parcelable { * Native bitmap has been reconfigured, so set premult and cached * width/height values */ - // called from JNI + @SuppressWarnings("unused") // called from JNI void reinit(int width, int height, boolean requestPremultiplied) { mWidth = width; mHeight = height; @@ -465,6 +465,15 @@ public final class Bitmap implements Parcelable { */ ARGB_8888 (5), + /** + * Each pixels is stored on 8 bytes. Each channel (RGB and alpha + * for translucency) is stored as a + * {@link android.util.Half half-precision floating point value}. + * + * This configuration is particularly suited for wide-gamut and + * HDR content. + */ + RGBA_F16 (6), /** * Special configuration, when bitmap is stored only in graphic memory. @@ -473,12 +482,12 @@ public final class Bitmap implements Parcelable { * It is optimal for cases, when the only operation with the bitmap is to draw it on a * screen. */ - HARDWARE (6); + HARDWARE (7); final int nativeInt; private static Config sConfigs[] = { - null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, HARDWARE + null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE }; Config(int ni) { @@ -760,6 +769,9 @@ public final class Bitmap implements Parcelable { case ALPHA_8: newConfig = Config.ALPHA_8; break; + case RGBA_F16: + newConfig = Config.RGBA_F16; + break; //noinspection deprecation case ARGB_4444: case ARGB_8888: @@ -781,8 +793,13 @@ public final class Bitmap implements Parcelable { neww = Math.round(deviceR.width()); newh = Math.round(deviceR.height()); - bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig, - transformed || source.hasAlpha()); + Config transformedConfig = newConfig; + if (transformed) { + if (transformedConfig != Config.ARGB_8888 && transformedConfig != Config.RGBA_F16) { + transformedConfig = Config.ARGB_8888; + } + } + bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha()); canvas.translate(-deviceR.left, -deviceR.top); canvas.concat(m); @@ -845,14 +862,14 @@ public final class Bitmap implements Parcelable { * @param width The width of the bitmap * @param height The height of the bitmap * @param config The bitmap config to create. - * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the - * bitmap as opaque. Doing so will clear the bitmap in black + * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to + * mark the bitmap as opaque. Doing so will clear the bitmap in black * instead of transparent. * * @throws IllegalArgumentException if the width or height are <= 0, or if * Config is Config.HARDWARE, because hardware bitmaps are always immutable */ - private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { + public static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { return createBitmap(null, width, height, config, hasAlpha); } @@ -865,14 +882,14 @@ public final class Bitmap implements Parcelable { * @param width The width of the bitmap * @param height The height of the bitmap * @param config The bitmap config to create. - * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the - * bitmap as opaque. Doing so will clear the bitmap in black + * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to + * mark the bitmap as opaque. Doing so will clear the bitmap in black * instead of transparent. * * @throws IllegalArgumentException if the width or height are <= 0, or if * Config is Config.HARDWARE, because hardware bitmaps are always immutable */ - private static Bitmap createBitmap(DisplayMetrics display, int width, int height, + public static Bitmap createBitmap(DisplayMetrics display, int width, int height, Config config, boolean hasAlpha) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); @@ -885,7 +902,7 @@ public final class Bitmap implements Parcelable { bm.mDensity = display.densityDpi; } bm.setHasAlpha(hasAlpha); - if (config == Config.ARGB_8888 && !hasAlpha) { + if ((config == Config.ARGB_8888 || config == Config.RGBA_F16) && !hasAlpha) { nativeErase(bm.mNativePtr, 0xff000000); } // No need to initialize the bitmap to zeroes with other configs; @@ -1526,7 +1543,7 @@ public final class Bitmap implements Parcelable { /** * <p>Replace pixels in the bitmap with the colors in the array. Each element - * in the array is a packed int prepresenting a non-premultiplied ARGB + * in the array is a packed int representing a non-premultiplied ARGB * {@link Color}.</p> * * @param pixels The colors to write to the bitmap diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 7dc5de3051e6..d968516f36bc 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1671,6 +1671,28 @@ public abstract class ColorSpace { } /** + * Converts values from CIE xyY to CIE L*u*v*. Y is assumed to be 1 so the + * input xyY array only contains the x and y components. After this method + * returns, the xyY array contains the converted u and v components. + * + * @param xyY The xyY value to convert to XYZ, cannot be null, + * length must be a multiple of 2 + */ + private static void xyYToUv(@NonNull @Size(multiple = 2) float[] xyY) { + for (int i = 0; i < xyY.length; i += 2) { + float x = xyY[i]; + float y = xyY[i + 1]; + + float d = -2.0f * x + 12.0f * y + 3; + float u = (4.0f * x) / d; + float v = (9.0f * y) / d; + + xyY[i] = u; + xyY[i + 1] = v; + } + } + + /** * <p>Computes the chromatic adaptation transform from the specified * source white point to the specified destination white point.</p> * @@ -3162,10 +3184,10 @@ public abstract class ColorSpace { /** * <p>A color space renderer can be used to visualize and compare the gamut and * white point of one or more color spaces. The output is an sRGB {@link Bitmap} - * showing a CIE 1931 xyY chromaticity diagram.</p> + * showing a CIE 1931 xyY or a CIE 1976 UCS chromaticity diagram.</p> * * <p>The following code snippet shows how to compare the {@link Named#SRGB} - * and {@link Named#DCI_P3} color spaces:</p> + * and {@link Named#DCI_P3} color spaces in a CIE 1931 diagram:</p> * * <pre class="prettyprint"> * Bitmap bitmap = ColorSpace.createRenderer() @@ -3188,12 +3210,18 @@ public abstract class ColorSpace { */ public static class Renderer { private static final int NATIVE_SIZE = 1440; + private static final float UCS_SCALE = 9.0f / 6.0f; + + // Number of subdivision of the inside of the spectral locus + private static final int CHROMATICITY_RESOLUTION = 32; + private static final double ONE_THIRD = 1.0 / 3.0; @IntRange(from = 128, to = Integer.MAX_VALUE) private int mSize = 1024; private boolean mShowWhitePoint = true; private boolean mClip = false; + private boolean mUcs = false; private final List<Pair<ColorSpace, Integer>> mColorSpaces = new ArrayList<>(2); private final List<Point> mPoints = new ArrayList<>(0); @@ -3241,6 +3269,35 @@ public abstract class ColorSpace { } /** + * <p>Defines whether the chromaticity diagram should use the uniform + * chromaticity scale (CIE 1976 UCS). When the uniform chromaticity scale + * is used, the distance between two points on the diagram is approximately + * proportional to the perceived color difference.</p> + * + * <p>The following code snippet shows how to enable the uniform chromaticity + * scale. The image below shows the result:</p> + * <pre class="prettyprint"> + * Bitmap bitmap = ColorSpace.createRenderer() + * .uniformChromaticityScale(true) + * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff) + * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845) + * .render(); + * </pre> + * <p> + * <img src="{@docRoot}reference/android/images/graphics/colorspace_ucs.png" /> + * <figcaption style="text-align: center;">CIE 1976 UCS diagram</figcaption> + * </p> + * + * @param ucs True to render the chromaticity diagram as the CIE 1976 UCS diagram + * @return This instance of {@link Renderer} + */ + @NonNull + public Renderer uniformChromaticityScale(boolean ucs) { + mUcs = ucs; + return this; + } + + /** * Sets the dimensions (width and height) in pixels of the output bitmap. * The size must be at least 128px and defaults to 1024px. * @@ -3302,7 +3359,7 @@ public abstract class ColorSpace { * </pre> * <p> * <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison2.png" /> - * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption> + * <figcaption style="text-align: center;">sRGB, DCI-P3, ACES and scRGB</figcaption> * </p> * * @param colorSpace The color space whose gamut to render on the diagram @@ -3385,6 +3442,7 @@ public abstract class ColorSpace { setTransform(canvas, width, height, primaries); drawBox(canvas, width, height, paint, path); + setUcsTransform(canvas, height); drawLocus(canvas, width, height, paint, path, primaries); drawGamuts(canvas, width, height, paint, path, primaries, whitePoint); drawPoints(canvas, width, height, paint); @@ -3406,7 +3464,11 @@ public abstract class ColorSpace { paint.setStyle(Paint.Style.FILL); + float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f); + float[] v = new float[3]; + float[] xy = new float[2]; + for (final Point point : mPoints) { v[0] = point.mRgb[0]; v[1] = point.mRgb[1]; @@ -3415,10 +3477,13 @@ public abstract class ColorSpace { paint.setColor(point.mColor); - // XYZ to xyY, assuming Y=1.0 + // XYZ to xyY, assuming Y=1.0, then to L*u*v* if needed float sum = v[0] + v[1] + v[2]; - canvas.drawCircle(width * v[0] / sum, height - height * v[1] / sum, - 4.0f, paint); + xy[0] = v[0] / sum; + xy[1] = v[1] / sum; + if (mUcs) xyYToUv(xy); + + canvas.drawCircle(width * xy[0], height - height * xy[1], radius, paint); } } @@ -3440,6 +3505,8 @@ public abstract class ColorSpace { @NonNull Paint paint, @NonNull Path path, @NonNull @Size(6) float[] primaries, @NonNull @Size(2) float[] whitePoint) { + float radius = 4.0f / (mUcs ? UCS_SCALE : 1.0f); + for (final Pair<ColorSpace, Integer> item : mColorSpaces) { ColorSpace colorSpace = item.first; int color = item.second; @@ -3447,7 +3514,7 @@ public abstract class ColorSpace { if (colorSpace.getModel() != Model.RGB) continue; Rgb rgb = (Rgb) colorSpace; - getPrimaries(rgb, primaries); + getPrimaries(rgb, primaries, mUcs); path.rewind(); path.moveTo(width * primaries[0], height - height * primaries[1]); @@ -3462,11 +3529,12 @@ public abstract class ColorSpace { // Draw the white point if (mShowWhitePoint) { rgb.getWhitePoint(whitePoint); + if (mUcs) xyYToUv(whitePoint); paint.setStyle(Paint.Style.FILL); paint.setColor(color); - canvas.drawCircle(width * whitePoint[0], height - height * whitePoint[1], - 4.0f, paint); + canvas.drawCircle( + width * whitePoint[0], height - height * whitePoint[1], radius, paint); } } } @@ -3477,10 +3545,12 @@ public abstract class ColorSpace { * * @param rgb The color space whose primaries to extract * @param primaries A pre-allocated array of 6 floats that will hold the result + * @param asUcs True if the primaries should be returned in Luv, false for xyY */ @NonNull @Size(6) - private static float[] getPrimaries(@NonNull Rgb rgb, @NonNull @Size(6) float[] primaries) { + private static float[] getPrimaries(@NonNull Rgb rgb, + @NonNull @Size(6) float[] primaries, boolean asUcs) { // TODO: We should find a better way to handle these cases if (rgb.equals(ColorSpace.get(Named.EXTENDED_SRGB)) || rgb.equals(ColorSpace.get(Named.LINEAR_EXTENDED_SRGB))) { @@ -3490,9 +3560,11 @@ public abstract class ColorSpace { primaries[3] = 1.24f; primaries[4] = -0.23f; primaries[5] = -0.57f; - return primaries; + } else { + rgb.getPrimaries(primaries); } - return rgb.getPrimaries(primaries); + if (asUcs) xyYToUv(primaries); + return primaries; } /** @@ -3513,7 +3585,13 @@ public abstract class ColorSpace { int vertexCount = SPECTRUM_LOCUS_X.length * CHROMATICITY_RESOLUTION * 6; float[] vertices = new float[vertexCount * 2]; int[] colors = new int[vertices.length]; - computeChromaticityMesh(NATIVE_SIZE, NATIVE_SIZE, vertices, colors); + computeChromaticityMesh(vertices, colors); + + if (mUcs) xyYToUv(vertices); + for (int i = 0; i < vertices.length; i += 2) { + vertices[i] *= width; + vertices[i + 1] = height - vertices[i + 1] * height; + } // Draw the spectral locus if (mClip && mColorSpaces.size() > 0) { @@ -3522,7 +3600,8 @@ public abstract class ColorSpace { if (colorSpace.getModel() != Model.RGB) continue; Rgb rgb = (Rgb) colorSpace; - getPrimaries(rgb, primaries); + getPrimaries(rgb, primaries, mUcs); + break; } @@ -3559,6 +3638,7 @@ public abstract class ColorSpace { } path.close(); + paint.setStrokeWidth(4.0f / (mUcs ? UCS_SCALE : 1.0f)); paint.setStyle(Paint.Style.STROKE); paint.setColor(0xff000000); canvas.drawPath(path, paint); @@ -3576,25 +3656,38 @@ public abstract class ColorSpace { */ private void drawBox(@NonNull Canvas canvas, int width, int height, @NonNull Paint paint, @NonNull Path path) { + + int lineCount = 10; + float scale = 1.0f; + if (mUcs) { + lineCount = 7; + scale = UCS_SCALE; + } + // Draw the unit grid paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2.0f); paint.setColor(0xffc0c0c0); - for (int i = 1; i <= 9; i++) { - canvas.drawLine(0.0f, height - (height * i / 10.0f), - 0.9f * width, height - (height * i / 10.0f), paint); - canvas.drawLine(width * i / 10.0f, height, - width * i / 10.0f, 0.1f * height, paint); + + for (int i = 1; i < lineCount - 1; i++) { + float v = i / 10.0f; + float x = (width * v) * scale; + float y = height - (height * v) * scale; + + canvas.drawLine(0.0f, y, 0.9f * width, y, paint); + canvas.drawLine(x, height, x, 0.1f * height, paint); } // Draw tick marks paint.setStrokeWidth(4.0f); paint.setColor(0xff000000); - for (int i = 1; i <= 9; i++) { - canvas.drawLine(0.0f, height - (height * i / 10.0f), - width / 100.0f, height - (height * i / 10.0f), paint); - canvas.drawLine(width * i / 10.0f, height, - width * i / 10.0f, height - (height / 100.0f), paint); + for (int i = 1; i < lineCount - 1; i++) { + float v = i / 10.0f; + float x = (width * v) * scale; + float y = height - (height * v) * scale; + + canvas.drawLine(0.0f, y, width / 100.0f, y, paint); + canvas.drawLine(x, height, x, height - (height / 100.0f), paint); } // Draw the axis labels @@ -3603,14 +3696,15 @@ public abstract class ColorSpace { paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL)); Rect bounds = new Rect(); - for (int i = 1; i < 9; i++) { + for (int i = 1; i < lineCount - 1; i++) { String text = "0." + i; paint.getTextBounds(text, 0, text.length(), bounds); - float y = height - (height * i / 10.0f); - canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint); + float v = i / 10.0f; + float x = (width * v) * scale; + float y = height - (height * v) * scale; - float x = width * i / 10.0f; + canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint); canvas.drawText(text, x - bounds.width() / 2.0f, height + bounds.height() + 16, paint); } @@ -3643,7 +3737,7 @@ public abstract class ColorSpace { if (colorSpace.getModel() != Model.RGB) continue; Rgb rgb = (Rgb) colorSpace; - getPrimaries(rgb, primaries); + getPrimaries(rgb, primaries, mUcs); primariesBounds.left = Math.min(primariesBounds.left, primaries[4]); primariesBounds.top = Math.min(primariesBounds.top, primaries[5]); @@ -3651,26 +3745,42 @@ public abstract class ColorSpace { primariesBounds.bottom = Math.max(primariesBounds.bottom, primaries[3]); } + float max = mUcs ? 0.6f : 0.9f; + primariesBounds.left = Math.min(0.0f, primariesBounds.left); primariesBounds.top = Math.min(0.0f, primariesBounds.top); - primariesBounds.right = Math.max(0.9f, primariesBounds.right); - primariesBounds.bottom = Math.max(0.9f, primariesBounds.bottom); + primariesBounds.right = Math.max(max, primariesBounds.right); + primariesBounds.bottom = Math.max(max, primariesBounds.bottom); - float scaleX = 0.9f / primariesBounds.width(); - float scaleY = 0.9f / primariesBounds.height(); + float scaleX = max / primariesBounds.width(); + float scaleY = max / primariesBounds.height(); float scale = Math.min(scaleX, scaleY); canvas.scale(mSize / (float) NATIVE_SIZE, mSize / (float) NATIVE_SIZE); canvas.scale(scale, scale); canvas.translate( - (primariesBounds.width() - 0.9f) * width / 2.0f, - (primariesBounds.height() - 0.9f) * height / 2.0f); + (primariesBounds.width() - max) * width / 2.0f, + (primariesBounds.height() - max) * height / 2.0f); // The spectrum extends ~0.85 vertically and ~0.65 horizontally // We shift the canvas a little bit to get nicer margins canvas.translate(0.05f * width, -0.05f * height); } + /** + * Computes and applies the Canvas transforms required to render the CIE + * 197 UCS chromaticity diagram. + * + * @param canvas The canvas to transform + * @param height Height in pixel of the final image + */ + private void setUcsTransform(@NonNull Canvas canvas, int height) { + if (mUcs) { + canvas.translate(0.0f, (height - height * UCS_SCALE)); + canvas.scale(UCS_SCALE, UCS_SCALE); + } + } + // X coordinates of the spectral locus in CIE 1931 private static final float[] SPECTRUM_LOCUS_X = { 0.175596f, 0.172787f, 0.170806f, 0.170085f, 0.160343f, @@ -3716,21 +3826,15 @@ public abstract class ColorSpace { 0.037799f, 0.029673f, 0.021547f, 0.013421f, 0.005295f }; - // Number of subdivision of the inside of the spectral locus - private static final int CHROMATICITY_RESOLUTION = 32; - private static final double ONE_THIRD = 1.0 / 3.0; - /** * Computes a 2D mesh representation of the CIE 1931 chromaticity * diagram. * - * @param width Width in pixels of the mesh - * @param height Height in pixels of the mesh * @param vertices Array of floats that will hold the mesh vertices * @param colors Array of floats that will hold the mesh colors */ - private static void computeChromaticityMesh(int width, int height, - @NonNull float[] vertices, @NonNull int[] colors) { + private static void computeChromaticityMesh(@NonNull float[] vertices, + @NonNull int[] colors) { ColorSpace colorSpace = get(Named.SRGB); @@ -3796,18 +3900,18 @@ public abstract class ColorSpace { colorIndex += 6; // Flip the mesh upside down to match Canvas' coordinates system - vertices[vertexIndex++] = v1x * width; - vertices[vertexIndex++] = height - v1y * height; - vertices[vertexIndex++] = v2x * width; - vertices[vertexIndex++] = height - v2y * height; - vertices[vertexIndex++] = v3x * width; - vertices[vertexIndex++] = height - v3y * height; - vertices[vertexIndex++] = v1x * width; - vertices[vertexIndex++] = height - v1y * height; - vertices[vertexIndex++] = v3x * width; - vertices[vertexIndex++] = height - v3y * height; - vertices[vertexIndex++] = v4x * width; - vertices[vertexIndex++] = height - v4y * height; + vertices[vertexIndex++] = v1x; + vertices[vertexIndex++] = v1y; + vertices[vertexIndex++] = v2x; + vertices[vertexIndex++] = v2y; + vertices[vertexIndex++] = v3x; + vertices[vertexIndex++] = v3y; + vertices[vertexIndex++] = v1x; + vertices[vertexIndex++] = v1y; + vertices[vertexIndex++] = v3x; + vertices[vertexIndex++] = v3y; + vertices[vertexIndex++] = v4x; + vertices[vertexIndex++] = v4y; } } } diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java index 98082cae8379..0fa52f895dd9 100644 --- a/graphics/java/android/graphics/PixelFormat.java +++ b/graphics/java/android/graphics/PixelFormat.java @@ -22,13 +22,17 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; public class PixelFormat { - /** @hide */ @IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE}) @Retention(RetentionPolicy.SOURCE) public @interface Opacity {} - /* these constants need to match those in hardware/hardware.h */ + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({RGBA_8888, RGBX_8888, RGBA_F16, RGBX_F16, RGB_888, RGB_565}) + public @interface Format { }; + + // NOTE: these constants must match the values from graphics/common/x.x/types.hal public static final int UNKNOWN = 0; @@ -62,7 +66,6 @@ public class PixelFormat { @Deprecated public static final int RGB_332 = 0xB; - /** * @deprecated use {@link android.graphics.ImageFormat#NV16 * ImageFormat.NV16} instead. @@ -84,6 +87,9 @@ public class PixelFormat { @Deprecated public static final int YCbCr_422_I = 0x14; + public static final int RGBA_F16 = 0x16; + public static final int RGBX_F16 = 0x17; + /** * @deprecated use {@link android.graphics.ImageFormat#JPEG * ImageFormat.JPEG} instead. @@ -91,7 +97,10 @@ public class PixelFormat { @Deprecated public static final int JPEG = 0x100; - public static void getPixelFormatInfo(int format, PixelFormat info) { + public int bytesPerPixel; + public int bitsPerPixel; + + public static void getPixelFormatInfo(@Format int format, PixelFormat info) { switch (format) { case RGBA_8888: case RGBX_8888: @@ -124,18 +133,24 @@ public class PixelFormat { info.bitsPerPixel = 12; info.bytesPerPixel = 1; break; + case RGBA_F16: + case RGBX_F16: + info.bitsPerPixel = 64; + info.bytesPerPixel = 8; + break; default: throw new IllegalArgumentException("unknown pixel format " + format); } } - public static boolean formatHasAlpha(int format) { + public static boolean formatHasAlpha(@Format int format) { switch (format) { case PixelFormat.A_8: case PixelFormat.LA_88: case PixelFormat.RGBA_4444: case PixelFormat.RGBA_5551: case PixelFormat.RGBA_8888: + case PixelFormat.RGBA_F16: case PixelFormat.TRANSLUCENT: case PixelFormat.TRANSPARENT: return true; @@ -143,9 +158,6 @@ public class PixelFormat { return false; } - public int bytesPerPixel; - public int bitsPerPixel; - /** * Determine whether or not this is a public-visible and non-deprecated {@code format}. * @@ -159,12 +171,14 @@ public class PixelFormat { * * @hide */ - public static boolean isPublicFormat(int format) { + public static boolean isPublicFormat(@Format int format) { switch (format) { case RGBA_8888: case RGBX_8888: case RGB_888: case RGB_565: + case RGBA_F16: + case RGBX_F16: return true; } diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp index 4c8abc5da832..938b6efa7901 100644 --- a/libs/hwui/OpenGLReadback.cpp +++ b/libs/hwui/OpenGLReadback.cpp @@ -131,6 +131,13 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, destWidth, destHeight, caches.maxTextureSize); return CopyResult::DestinationInvalid; } + + // TODO: Add support for RGBA_F16 destinations + if (bitmap->colorType() == kRGBA_F16_SkColorType) { + ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); + return CopyResult::DestinationInvalid; + } + GLuint fbo = renderState.createFramebuffer(); if (!fbo) { ALOGW("Could not obtain an FBO"); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 5b5b74e1c3f3..705395e1e2b7 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -225,6 +225,12 @@ void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType color *outInternalFormat = GL_LUMINANCE; *outType = GL_UNSIGNED_BYTE; break; + case kRGBA_F16_SkColorType: + // This format is always linear + *outFormat = GL_RGBA; + *outInternalFormat = GL_RGBA16F; + *outType = GL_HALF_FLOAT; + break; default: LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType); break; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 2177af1773e5..a9058b1fb6f6 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -108,6 +108,8 @@ static PixelFormat internalFormatToPixelFormat(GLint internalFormat) { return PIXEL_FORMAT_RGBA_8888; case GL_RGB: return PIXEL_FORMAT_RGB_565; + case GL_RGBA16F: + return PIXEL_FORMAT_RGBA_FP16; default: LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat); return PIXEL_FORMAT_UNKNOWN; @@ -306,7 +308,8 @@ sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) { PixelFormat format = graphicBuffer->getPixelFormat(); - if (!graphicBuffer.get() || format != PIXEL_FORMAT_RGBA_8888) { + if (!graphicBuffer.get() || + (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) { return nullptr; } SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(), |