summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/hwui/Bitmap.cpp57
-rw-r--r--libs/hwui/hwui/Bitmap.h22
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp47
-rw-r--r--libs/hwui/hwui/ImageDecoder.h8
-rw-r--r--libs/hwui/pipeline/skia/ATraceMemoryDump.cpp41
-rw-r--r--libs/hwui/pipeline/skia/ATraceMemoryDump.h4
6 files changed, 124 insertions, 55 deletions
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 84549e8ce6e4..3c402e996218 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -38,7 +38,7 @@
#include <SkCanvas.h>
#include <SkImagePriv.h>
-
+#include <SkWebpEncoder.h>
#include <SkHighContrastFilter.h>
#include <limits>
@@ -471,4 +471,59 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr,
return BitmapPalette::Unknown;
}
+Bitmap::CompressResult Bitmap::compress(JavaCompressFormat format, int32_t quality,
+ SkWStream* stream) {
+ SkBitmap skbitmap;
+ getSkBitmap(&skbitmap);
+ return compress(skbitmap, format, quality, stream);
+}
+
+Bitmap::CompressResult Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
+ int32_t quality, SkWStream* stream) {
+ SkBitmap skbitmap = bitmap;
+ if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
+ // Convert to P3 before encoding. This matches
+ // SkAndroidCodec::computeOutputColorSpace for wide gamuts. Now that F16
+ // could already be P3, we still want to convert to 8888.
+ auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
+ auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
+ .makeColorSpace(std::move(cs));
+ SkBitmap p3;
+ if (!p3.tryAllocPixels(info)) {
+ return CompressResult::AllocationFailed;
+ }
+
+ SkPixmap pm;
+ SkAssertResult(p3.peekPixels(&pm)); // should always work if tryAllocPixels() did.
+ if (!skbitmap.readPixels(pm)) {
+ return CompressResult::Error;
+ }
+ skbitmap = p3;
+ }
+
+ SkEncodedImageFormat fm;
+ switch (format) {
+ case JavaCompressFormat::Jpeg:
+ fm = SkEncodedImageFormat::kJPEG;
+ break;
+ case JavaCompressFormat::Png:
+ fm = SkEncodedImageFormat::kPNG;
+ break;
+ case JavaCompressFormat::Webp:
+ fm = SkEncodedImageFormat::kWEBP;
+ break;
+ case JavaCompressFormat::WebpLossy:
+ case JavaCompressFormat::WebpLossless: {
+ SkWebpEncoder::Options options;
+ options.fQuality = quality;
+ options.fCompression = format == JavaCompressFormat::WebpLossy ?
+ SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless;
+ return SkWebpEncoder::Encode(stream, skbitmap.pixmap(), options)
+ ? CompressResult::Success : CompressResult::Error;
+ }
+ }
+
+ return SkEncodeImage(stream, skbitmap, fm, quality)
+ ? CompressResult::Success : CompressResult::Error;
+}
} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 1cda0465ae64..ee365af2f7be 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -27,6 +27,8 @@
#include <android/hardware_buffer.h>
#endif
+class SkWStream;
+
namespace android {
enum class PixelStorageType {
@@ -142,6 +144,26 @@ public:
// and places that value in size.
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size);
+ // These must match the int values of CompressFormat in Bitmap.java, as well as
+ // AndroidBitmapCompressFormat.
+ enum class JavaCompressFormat {
+ Jpeg = 0,
+ Png = 1,
+ Webp = 2,
+ WebpLossy = 3,
+ WebpLossless = 4,
+ };
+
+ enum class CompressResult {
+ Success,
+ AllocationFailed,
+ Error,
+ };
+
+ CompressResult compress(JavaCompressFormat format, int32_t quality, SkWStream* stream);
+
+ static CompressResult compress(const SkBitmap& bitmap, JavaCompressFormat format,
+ int32_t quality, SkWStream* stream);
private:
static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 4f2027d978a1..a6c4e9db7280 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -30,19 +30,25 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu
, mTargetSize(mCodec->getInfo().dimensions())
, mDecodeSize(mTargetSize)
, mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
- , mOutAlphaType(mCodec->getInfo().isOpaque() ?
- kOpaque_SkAlphaType : kPremul_SkAlphaType)
+ , mUnpremultipliedRequired(false)
, mOutColorSpace(mCodec->getInfo().refColorSpace())
, mSampleSize(1)
{
}
+SkAlphaType ImageDecoder::getOutAlphaType() const {
+ // While an SkBitmap may want to use kOpaque_SkAlphaType for a performance
+ // optimization, this class just outputs raw pixels. Using either
+ // premultiplication choice has no effect on decoding an opaque encoded image.
+ return mUnpremultipliedRequired ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
+}
+
bool ImageDecoder::setTargetSize(int width, int height) {
if (width <= 0 || height <= 0) {
return false;
}
- auto info = SkImageInfo::Make(width, height, mOutColorType, mOutAlphaType);
+ auto info = SkImageInfo::Make(width, height, mOutColorType, getOutAlphaType());
size_t rowBytes = info.minRowBytes();
if (rowBytes == 0) {
// This would have overflowed.
@@ -63,7 +69,7 @@ bool ImageDecoder::setTargetSize(int width, int height) {
SkISize targetSize = { width, height }, decodeSize = targetSize;
int sampleSize = mCodec->computeSampleSize(&decodeSize);
- if (decodeSize != targetSize && mOutAlphaType == kUnpremul_SkAlphaType
+ if (decodeSize != targetSize && mUnpremultipliedRequired
&& !mCodec->getInfo().isOpaque()) {
return false;
}
@@ -119,29 +125,11 @@ bool ImageDecoder::setOutColorType(SkColorType colorType) {
return true;
}
-bool ImageDecoder::setOutAlphaType(SkAlphaType alpha) {
- switch (alpha) {
- case kOpaque_SkAlphaType:
- return opaque();
- case kPremul_SkAlphaType:
- if (opaque()) {
- // Opaque can be treated as premul.
- return true;
- }
- break;
- case kUnpremul_SkAlphaType:
- if (opaque()) {
- // Opaque can be treated as unpremul.
- return true;
- }
- if (mDecodeSize != mTargetSize) {
- return false;
- }
- break;
- default:
- return false;
+bool ImageDecoder::setUnpremultipliedRequired(bool required) {
+ if (required && !opaque() && mDecodeSize != mTargetSize) {
+ return false;
}
- mOutAlphaType = alpha;
+ mUnpremultipliedRequired = required;
return true;
}
@@ -151,11 +139,11 @@ void ImageDecoder::setOutColorSpace(sk_sp<SkColorSpace> colorSpace) {
SkImageInfo ImageDecoder::getOutputInfo() const {
SkISize size = mCropRect ? mCropRect->size() : mTargetSize;
- return SkImageInfo::Make(size, mOutColorType, mOutAlphaType, mOutColorSpace);
+ return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), mOutColorSpace);
}
bool ImageDecoder::opaque() const {
- return mOutAlphaType == kOpaque_SkAlphaType;
+ return mCodec->getInfo().alphaType() == kOpaque_SkAlphaType;
}
bool ImageDecoder::gray() const {
@@ -165,7 +153,8 @@ bool ImageDecoder::gray() const {
SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
void* decodePixels = pixels;
size_t decodeRowBytes = rowBytes;
- auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, mOutAlphaType, mOutColorSpace);
+ auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
+ mOutColorSpace);
// Used if we need a temporary before scaling or subsetting.
// FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
SkBitmap tmp;
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index b956f4a77793..96f97e5421f3 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -41,14 +41,12 @@ public:
bool setOutColorType(SkColorType outColorType);
- bool setOutAlphaType(SkAlphaType outAlphaType);
+ bool setUnpremultipliedRequired(bool unpremultipliedRequired);
void setOutColorSpace(sk_sp<SkColorSpace> cs);
// The size is the final size after scaling and cropping.
SkImageInfo getOutputInfo() const;
- SkColorType getOutColorType() const { return mOutColorType; }
- SkAlphaType getOutAlphaType() const { return mOutAlphaType; }
bool opaque() const;
bool gray() const;
@@ -59,13 +57,15 @@ private:
SkISize mTargetSize;
SkISize mDecodeSize;
SkColorType mOutColorType;
- SkAlphaType mOutAlphaType;
+ bool mUnpremultipliedRequired;
sk_sp<SkColorSpace> mOutColorSpace;
int mSampleSize;
std::optional<SkIRect> mCropRect;
ImageDecoder(const ImageDecoder&) = delete;
ImageDecoder& operator=(const ImageDecoder&) = delete;
+
+ SkAlphaType getOutAlphaType() const;
};
} // namespace android
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 2c78b024536b..551bdc63121d 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -24,8 +24,8 @@ namespace android {
namespace uirenderer {
namespace skiapipeline {
-// When purgeable is INVALID_TIME it won't be logged at all.
-#define INVALID_TIME -1
+// When purgeable is INVALID_MEMORY_SIZE it won't be logged at all.
+#define INVALID_MEMORY_SIZE -1
/**
* Skia invokes the following SkTraceMemoryDump functions:
@@ -42,10 +42,10 @@ namespace skiapipeline {
* "GPU Memory" category.
*/
static std::unordered_map<const char*, const char*> sResourceMap = {
- {"malloc", "Graphics CPU Memory"}, // taken from setMemoryBacking(backingType)
- {"gl_texture", "Graphics Texture Memory"}, // taken from setMemoryBacking(backingType)
+ {"malloc", "HWUI CPU Memory"}, // taken from setMemoryBacking(backingType)
+ {"gl_texture", "HWUI Texture Memory"}, // taken from setMemoryBacking(backingType)
{"Texture",
- "Graphics Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
+ "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
// Uncomment categories below to split "GPU Memory" into more brackets for debugging.
/*{"vk_buffer", "vk_buffer"},
{"gl_renderbuffer", "gl_renderbuffer"},
@@ -105,10 +105,10 @@ void ATraceMemoryDump::startFrame() {
// Once a category is observed in at least one frame, it is always reported in subsequent
// frames (even if it is 0). Not logging a category to ATRACE would mean its value has not
// changed since the previous frame, which is not what we want.
- it.second.time = 0;
- // If purgeableTime is INVALID_TIME, then logTraces won't log it at all.
- if (it.second.purgeableTime != INVALID_TIME) {
- it.second.purgeableTime = 0;
+ it.second.memory = 0;
+ // If purgeableMemory is INVALID_MEMORY_SIZE, then logTraces won't log it at all.
+ if (it.second.purgeableMemory != INVALID_MEMORY_SIZE) {
+ it.second.purgeableMemory = 0;
}
}
}
@@ -119,12 +119,15 @@ void ATraceMemoryDump::startFrame() {
void ATraceMemoryDump::logTraces() {
// Accumulate data from last dumpName
recordAndResetCountersIfNeeded("");
+ uint64_t hwui_all_frame_memory = 0;
for (auto& it : mCurrentValues) {
- ATRACE_INT64(it.first.c_str(), it.second.time);
- if (it.second.purgeableTime != INVALID_TIME) {
- ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableTime);
+ hwui_all_frame_memory += it.second.memory;
+ ATRACE_INT64(it.first.c_str(), it.second.memory);
+ if (it.second.purgeableMemory != INVALID_MEMORY_SIZE) {
+ ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableMemory);
}
}
+ ATRACE_INT64("HWUI All Memory", hwui_all_frame_memory);
}
/**
@@ -145,12 +148,12 @@ void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) {
// A new dumpName observed -> store the data already collected.
auto memoryCounter = mCurrentValues.find(mCategory);
if (memoryCounter != mCurrentValues.end()) {
- memoryCounter->second.time += mLastDumpValue;
- if (mLastPurgeableDumpValue != INVALID_TIME) {
- if (memoryCounter->second.purgeableTime == INVALID_TIME) {
- memoryCounter->second.purgeableTime = mLastPurgeableDumpValue;
+ memoryCounter->second.memory += mLastDumpValue;
+ if (mLastPurgeableDumpValue != INVALID_MEMORY_SIZE) {
+ if (memoryCounter->second.purgeableMemory == INVALID_MEMORY_SIZE) {
+ memoryCounter->second.purgeableMemory = mLastPurgeableDumpValue;
} else {
- memoryCounter->second.purgeableTime += mLastPurgeableDumpValue;
+ memoryCounter->second.purgeableMemory += mLastPurgeableDumpValue;
}
}
} else {
@@ -164,10 +167,10 @@ void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) {
void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) {
mLastDumpValue = 0;
- mLastPurgeableDumpValue = INVALID_TIME;
+ mLastPurgeableDumpValue = INVALID_MEMORY_SIZE;
mLastDumpName = dumpName;
// Categories not listed in sResourceMap are reported as "GPU memory"
- mCategory = "GPU Memory";
+ mCategory = "HWUI GPU Memory";
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.h b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
index aa5c401ad1ca..4592711dd5b5 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.h
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
@@ -62,8 +62,8 @@ private:
std::string mCategory;
struct TraceValue {
- uint64_t time;
- uint64_t purgeableTime;
+ uint64_t memory;
+ uint64_t purgeableMemory;
};
// keys are define in sResourceMap