diff --git a/api/current.txt b/api/current.txt index cec2b9fc24577..89573ace6dac8 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); 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); - method public synchronized boolean addAll(int, java.util.Collection); - method public synchronized int addAllAbsent(java.util.Collection); - 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); + method public boolean addAll(int, java.util.Collection); + method public int addAllAbsent(java.util.Collection); + 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); 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 iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator 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 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 subList(int, int); method public java.lang.Object[] toArray(); diff --git a/api/system-current.txt b/api/system-current.txt index f718451fbe8a7..870070b7803b1 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 @@ -64944,31 +64950,31 @@ package java.util.concurrent { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(java.util.Collection); 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); - method public synchronized boolean addAll(int, java.util.Collection); - method public synchronized int addAllAbsent(java.util.Collection); - 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); + method public boolean addAll(int, java.util.Collection); + method public int addAllAbsent(java.util.Collection); + 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); 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 iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator 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 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 subList(int, int); method public java.lang.Object[] toArray(); diff --git a/api/test-current.txt b/api/test-current.txt index b61fc9e1f2158..10554ff012d60 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 @@ -61731,31 +61737,31 @@ package java.util.concurrent { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(java.util.Collection); 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); - method public synchronized boolean addAll(int, java.util.Collection); - method public synchronized int addAllAbsent(java.util.Collection); - 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); + method public boolean addAll(int, java.util.Collection); + method public int addAllAbsent(java.util.Collection); + 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); 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 iterator(); - method public int lastIndexOf(E, int); method public int lastIndexOf(java.lang.Object); - method public java.util.ListIterator listIterator(int); + method public int lastIndexOf(E, int); method public java.util.ListIterator 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 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 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 673cf863391c0..b656bb08cba91 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(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(array), - JNI_ABORT); + env->ReleaseIntArrayElements(srcColors, const_cast(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 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 bitmap(new SkBitmap); - if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, - isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) { + sk_sp 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 18ed0ed72190e..69c7054949322 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 codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), - &peeker)); + std::unique_ptr 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 d8984d3367468..6f97c600a1cc2 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 GraphicsJNI::defaultColorSpace() { #endif } +sk_sp GraphicsJNI::linearColorSpace() { + return SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); +} + +sk_sp 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 03dc1fbe82faf..508c9ffd0f205 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 defaultColorSpace(); + static sk_sp linearColorSpace(); + static sk_sp colorSpaceForType(SkColorType type); }; class HeapAllocator : public SkBRDAllocator { diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index b6b5245978962..bb69e27933b22 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 92693b7104248..a5b7671fa1aca 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 5b8818171b6f0..62c3d04f117bc 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 3c8db7fd3c3d7..d3c0202154859 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 new file mode 100644 index 0000000000000..3e0f0c6f0cc40 Binary files /dev/null and b/docs/html/reference/images/graphics/colorspace_ucs.png differ diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index cd75fe95121ae..a041a28010e24 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 { /** *

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}.

* * @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 7dc5de3051e65..d968516f36bc3 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1670,6 +1670,28 @@ public abstract class ColorSpace { return new float[] { xyY[0] / xyY[1], 1.0f, (1 - xyY[0] - xyY[1]) / xyY[1] }; } + /** + * 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; + } + } + /** *

Computes the chromatic adaptation transform from the specified * source white point to the specified destination white point.

@@ -3162,10 +3184,10 @@ public abstract class ColorSpace { /** *

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.

+ * showing a CIE 1931 xyY or a CIE 1976 UCS chromaticity diagram.

* *

The following code snippet shows how to compare the {@link Named#SRGB} - * and {@link Named#DCI_P3} color spaces:

+ * and {@link Named#DCI_P3} color spaces in a CIE 1931 diagram:

* *
      * 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> mColorSpaces = new ArrayList<>(2);
         private final List mPoints = new ArrayList<>(0);
@@ -3240,6 +3268,35 @@ public abstract class ColorSpace {
             return this;
         }
 
+        /**
+         * 

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.

+ * + *

The following code snippet shows how to enable the uniform chromaticity + * scale. The image below shows the result:

+ *
+         * Bitmap bitmap = ColorSpace.createRenderer()
+         *     .uniformChromaticityScale(true)
+         *     .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+         *     .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+         *     .render();
+         * 
+ *

+ * + *

CIE 1976 UCS diagram
+ *

+ * + * @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 { *
*

* - *

sRGB vs DCI-P3
+ *
sRGB, DCI-P3, ACES and scRGB
*

* * @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 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 98082cae83791..0fa52f895dd9e 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 4c8abc5da8328..938b6efa79015 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 5b5b74e1c3f3f..705395e1e2b7f 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 2177af1773e5e..a9058b1fb6f62 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::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) sk_sp Bitmap::createFrom(sp 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(),