diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 3 | ||||
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 5 | ||||
| -rw-r--r-- | libs/hwui/hwui/Bitmap.cpp | 57 | ||||
| -rw-r--r-- | libs/hwui/hwui/Bitmap.h | 22 | ||||
| -rw-r--r-- | libs/hwui/hwui/ImageDecoder.cpp | 47 | ||||
| -rw-r--r-- | libs/hwui/hwui/ImageDecoder.h | 8 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/ATraceMemoryDump.cpp | 41 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/ATraceMemoryDump.h | 4 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.cpp | 12 | ||||
| -rw-r--r-- | libs/hwui/utils/Color.cpp | 22 |
10 files changed, 158 insertions, 63 deletions
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index d6b516fd5cf4..5a50245a3765 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -18,6 +18,8 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. +#include <surfacetexture/surface_texture_platform.h> #include "AutoBackendTextureRelease.h" #include "Matrix.h" #include "Properties.h" @@ -34,6 +36,7 @@ namespace uirenderer { DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) : mRenderState(renderState) , mBlend(false) + , mSurfaceTexture(nullptr, [](ASurfaceTexture*) {}) , mTransform(nullptr) , mGLContextAttached(false) , mUpdateTexImage(false) diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 289f65c22ad3..c44c0d537fa7 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -21,8 +21,7 @@ #include <SkMatrix.h> #include <android/hardware_buffer.h> #include <cutils/compiler.h> -// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. -#include <gui/surfacetexture/surface_texture_platform.h> +#include <android/surface_texture.h> #include <map> #include <memory> @@ -37,7 +36,7 @@ namespace uirenderer { class AutoBackendTextureRelease; class RenderState; -typedef std::unique_ptr<ASurfaceTexture> AutoTextureRelease; +typedef std::unique_ptr<ASurfaceTexture, decltype(&ASurfaceTexture_release)> AutoTextureRelease; // Container to hold the properties a layer should be set to at the start // of a render pass 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 diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 35a885f46919..b940cff04713 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -458,9 +458,15 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip, const SkMatrix& preTransform) { SkAutoCanvasRestore saver(canvas, true); auto clipRestriction = preTransform.mapRect(clip).roundOut(); - canvas->androidFramework_setDeviceClipRestriction(clipRestriction); - canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction", - nullptr); + if (CC_UNLIKELY(mCaptureMode == CaptureMode::SingleFrameSKP + || mCaptureMode == CaptureMode::MultiFrameSKP)) { + canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction", + nullptr); + } else { + // clip drawing to dirty region only when not recording SKP files (which should contain all + // draw ops on every frame) + canvas->androidFramework_setDeviceClipRestriction(clipRestriction); + } canvas->concat(preTransform); // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293 diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index b93759f87da2..c445885c5c63 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -108,10 +108,26 @@ SkColorType PixelFormatToColorType(android::PixelFormat format) { } } +// FIXME: Share with the version in android_bitmap.cpp? +// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut +// matches the white point used by ColorSpace.Named.DCIP3. +static constexpr skcms_Matrix3x3 kDCIP3 = {{ + {0.486143, 0.323835, 0.154234}, + {0.226676, 0.710327, 0.0629966}, + {0.000800549, 0.0432385, 0.78275}, +}}; + sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { if (dataspace == HAL_DATASPACE_UNKNOWN) { return SkColorSpace::MakeSRGB(); } + if (dataspace == HAL_DATASPACE_DCI_P3) { + // This cannot be handled by the switch statements below because it + // needs to use the locally-defined kDCIP3 gamut, rather than the one in + // Skia (SkNamedGamut), which is used for other data spaces with + // HAL_DATASPACE_STANDARD_DCI_P3 (e.g. HAL_DATASPACE_DISPLAY_P3). + return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, kDCIP3); + } skcms_Matrix3x3 gamut; switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { @@ -152,10 +168,12 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); case HAL_DATASPACE_TRANSFER_GAMMA2_8: return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); + case HAL_DATASPACE_TRANSFER_ST2084: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut); + case HAL_DATASPACE_TRANSFER_SMPTE_170M: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut); case HAL_DATASPACE_TRANSFER_UNSPECIFIED: return nullptr; - case HAL_DATASPACE_TRANSFER_SMPTE_170M: - case HAL_DATASPACE_TRANSFER_ST2084: case HAL_DATASPACE_TRANSFER_HLG: default: ALOGV("Unsupported Gamma: %d", dataspace); |