diff options
Diffstat (limited to 'libs')
41 files changed, 655 insertions, 372 deletions
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index f7fb89e54ef3..2fe98b00f3a2 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -7035,40 +7035,70 @@ status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { return NO_ERROR; } -struct IdmapMatchingResources { - void Add(uint32_t targetResId, uint32_t overlayResId) { - uint8_t targetTypeid = Res_GETTYPE(targetResId); - if (typeMappings.find(targetTypeid) == typeMappings.end()) { - typeMappings.emplace(targetTypeid, std::set<std::pair<uint32_t, uint32_t>>()); +class IdmapMatchingResources; + +class IdmapTypeMapping { +public: + void add(uint32_t targetResId, uint32_t overlayResId) { + uint8_t targetTypeId = Res_GETTYPE(targetResId); + if (mData.find(targetTypeId) == mData.end()) { + mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>()); } - auto& entries = typeMappings[targetTypeid]; + auto& entries = mData[targetTypeId]; entries.insert(std::make_pair(targetResId, overlayResId)); } - void FixPadding() { - for (auto ti = typeMappings.cbegin(); ti != typeMappings.cend(); ++ti) { - uint32_t last_seen = 0xffffffff; - size_t total_entries = 0; + bool empty() const { + return mData.empty(); + } + +private: + // resource type ID in context of target -> set of resource entries mapping target -> overlay + std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> mData; + + friend IdmapMatchingResources; +}; + +class IdmapMatchingResources { +public: + IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm) : mTypeMapping(std::move(tm)) { + assert(mTypeMapping); + for (auto ti = mTypeMapping->mData.cbegin(); ti != mTypeMapping->mData.cend(); ++ti) { + uint32_t lastSeen = 0xffffffff; + size_t totalEntries = 0; for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) { - assert(last_seen == 0xffffffff || last_seen < ei->first); - entryPadding[ei->first] = (last_seen == 0xffffffff) ? 0 : ei->first - last_seen - 1; - last_seen = ei->first; - total_entries += 1 + entryPadding[ei->first]; + assert(lastSeen == 0xffffffff || lastSeen < ei->first); + mEntryPadding[ei->first] = (lastSeen == 0xffffffff) ? 0 : ei->first - lastSeen - 1; + lastSeen = ei->first; + totalEntries += 1 + mEntryPadding[ei->first]; } - numberOfEntriesIncludingPadding[ti->first] = total_entries; + mNumberOfEntriesIncludingPadding[ti->first] = totalEntries; } } + const auto& getTypeMapping() const { + return mTypeMapping->mData; + } + + size_t getNumberOfEntriesIncludingPadding(uint8_t type) const { + return mNumberOfEntriesIncludingPadding.at(type); + } + + size_t getPadding(uint32_t resid) const { + return mEntryPadding.at(resid); + } + +private: // resource type ID in context of target -> set of resource entries mapping target -> overlay - std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> typeMappings; + const std::unique_ptr<IdmapTypeMapping> mTypeMapping; // resource ID in context of target -> trailing padding for that resource (call FixPadding // before use) - std::map<uint32_t, size_t> entryPadding; + std::map<uint32_t, size_t> mEntryPadding; // resource type ID in context of target -> total number of entries, including padding entries, // for that type (call FixPadding before use) - std::map<uint8_t, size_t> numberOfEntriesIncludingPadding; + std::map<uint8_t, size_t> mNumberOfEntriesIncludingPadding; }; status_t ResTable::createIdmap(const ResTable& targetResTable, @@ -7098,7 +7128,8 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, return UNKNOWN_ERROR; } - const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package; + const ResTable_package* targetPackageStruct = + targetResTable.mPackageGroups[0]->packages[0]->package; const size_t tmpNameSize = arraysize(targetPackageStruct->name); char16_t tmpName[tmpNameSize]; strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize); @@ -7110,7 +7141,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, size_t forcedOverlayCount = 0u; // find the resources that exist in both packages - IdmapMatchingResources matchingResources; + auto typeMapping = std::make_unique<IdmapTypeMapping>(); for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) { const TypeList& typeList = packageGroup->types[typeIndex]; if (typeList.isEmpty()) { @@ -7144,24 +7175,25 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, ++forcedOverlayCount; } - matchingResources.Add(target_resid, overlay_resid); + typeMapping->add(target_resid, overlay_resid); } } - if (matchingResources.typeMappings.empty()) { + if (typeMapping->empty()) { ALOGE("idmap: no matching resources"); return UNKNOWN_ERROR; } - matchingResources.FixPadding(); + const IdmapMatchingResources matchingResources(std::move(typeMapping)); // write idmap *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc *outSize += 2 * sizeof(uint16_t); // target package id, type count - const auto typesEnd = matchingResources.typeMappings.cend(); - for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { + auto fixedTypeMapping = matchingResources.getTypeMapping(); + const auto typesEnd = fixedTypeMapping.cend(); + for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) { *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset - *outSize += matchingResources.numberOfEntriesIncludingPadding[ti->first] * + *outSize += matchingResources.getNumberOfEntriesIncludingPadding(ti->first) * sizeof(uint32_t); // entries } if ((*outData = malloc(*outSize)) == NULL) { @@ -7190,11 +7222,11 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, uint16_t* typeData = reinterpret_cast<uint16_t*>(data); *typeData++ = htods(targetPackageStruct->id); // write: target package id *typeData++ = - htods(static_cast<uint16_t>(matchingResources.typeMappings.size())); // write: type count + htods(static_cast<uint16_t>(fixedTypeMapping.size())); // write: type count // write idmap data - for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { - const size_t entryCount = matchingResources.numberOfEntriesIncludingPadding[ti->first]; + for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) { + const size_t entryCount = matchingResources.getNumberOfEntriesIncludingPadding(ti->first); auto ei = ti->second.cbegin(); *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id @@ -7202,7 +7234,7 @@ status_t ResTable::createIdmap(const ResTable& targetResTable, *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData); for (; ei != ti->second.cend(); ++ei) { - const size_t padding = matchingResources.entryPadding[ei->first]; + const size_t padding = matchingResources.getPadding(ei->first); for (size_t i = 0; i < padding; ++i) { *entryData++ = htodl(0xffffffff); // write: padding } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 17d2db71ab58..5f27faed08f3 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -45,9 +45,6 @@ cc_defaults { ], product_variables: { - device_uses_hwc2: { - cflags: ["-DUSE_HWC2"], - }, eng: { lto: { never: true, @@ -182,6 +179,7 @@ cc_defaults { "renderthread/CanvasContext.cpp", "renderthread/DrawFrameTask.cpp", "renderthread/EglManager.cpp", + "renderthread/ReliableSurface.cpp", "renderthread/VulkanManager.cpp", "renderthread/RenderProxy.cpp", "renderthread/RenderTask.cpp", diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index b772e5b87f2a..3bee3018d36e 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -85,19 +85,18 @@ void DeferredLayerUpdater::apply() { mUpdateTexImage = false; sk_sp<SkImage> layerImage; SkMatrix textureTransform; - android_dataspace dataSpace; bool queueEmpty = true; // If the SurfaceTexture queue is in synchronous mode, need to discard all // but latest frame. Since we can't tell which mode it is in, // do this unconditionally. do { - layerImage = mSurfaceTexture->dequeueImage(textureTransform, dataSpace, &queueEmpty, + layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty, mRenderState); } while (layerImage.get() && (!queueEmpty)); if (layerImage.get()) { // force filtration if buffer size != layer size bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); - updateLayer(forceFilter, textureTransform, dataSpace, layerImage); + updateLayer(forceFilter, textureTransform, layerImage); } } @@ -109,12 +108,11 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage) { + const sk_sp<SkImage>& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); mLayer->getTexTransform() = textureTransform; - mLayer->setDataSpace(dataspace); mLayer->setImage(layerImage); } diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index b2c5131dd613..a91c111933c4 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -95,7 +95,7 @@ public: void detachSurfaceTexture(); void updateLayer(bool forceFilter, const SkMatrix& textureTransform, - android_dataspace dataspace, const sk_sp<SkImage>& layerImage); + const sk_sp<SkImage>& layerImage); void destroyLayer(); diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index e7ae7675f0b8..ccbb6c10d3af 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -82,7 +82,6 @@ static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync; JankTracker::JankTracker(ProfileDataContainer* globalData, const DisplayInfo& displayInfo) { mGlobalData = globalData; nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / displayInfo.fps); -#if USE_HWC2 nsecs_t sfOffset = frameIntervalNanos - (displayInfo.presentationDeadline - 1_ms); nsecs_t offsetDelta = sfOffset - displayInfo.appVsyncOffset; // There are two different offset cases. If the offsetDelta is positive @@ -96,7 +95,6 @@ JankTracker::JankTracker(ProfileDataContainer* globalData, const DisplayInfo& di // return due to the staggering of VSYNC-app & VSYNC-sf. mDequeueTimeForgiveness = offsetDelta + 4_ms; } -#endif setFrameInterval(frameIntervalNanos); } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 32aaa54e696c..d0df200d2fa6 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -33,7 +33,6 @@ Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alp // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); - buildColorSpaceWithFilter(); renderState.registerLayer(this); texTransform.setIdentity(); transform.setIdentity(); @@ -43,36 +42,6 @@ Layer::~Layer() { mRenderState.unregisterLayer(this); } -void Layer::setColorFilter(sk_sp<SkColorFilter> filter) { - if (filter != mColorFilter) { - mColorFilter = filter; - buildColorSpaceWithFilter(); - } -} - -void Layer::setDataSpace(android_dataspace dataspace) { - if (dataspace != mCurrentDataspace) { - mCurrentDataspace = dataspace; - buildColorSpaceWithFilter(); - } -} - -void Layer::buildColorSpaceWithFilter() { - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - - if (mColorFilter && colorSpaceFilter) { - mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter); - } else if (colorSpaceFilter) { - mColorSpaceWithFilter = colorSpaceFilter; - } else { - mColorSpaceWithFilter = mColorFilter; - } -} - void Layer::postDecStrong() { mRenderState.postDecStrong(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e4f96e914c36..98600dbf1eea 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -69,15 +69,9 @@ public: SkBlendMode getMode() const; - inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); } + inline sk_sp<SkColorFilter> getColorFilter() const { return mColorFilter; } - void setColorFilter(sk_sp<SkColorFilter> filter); - - void setDataSpace(android_dataspace dataspace); - - void setColorSpace(sk_sp<SkColorSpace> colorSpace); - - inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; } + void setColorFilter(sk_sp<SkColorFilter> filter) { mColorFilter = filter; }; inline SkMatrix& getTexTransform() { return texTransform; } @@ -98,24 +92,12 @@ protected: RenderState& mRenderState; private: - void buildColorSpaceWithFilter(); - /** * Color filter used to draw this layer. Optional. */ sk_sp<SkColorFilter> mColorFilter; /** - * Colorspace of the contents of the layer. Optional. - */ - android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN; - - /** - * A color filter that is the combination of the mColorFilter and mColorSpace. Optional. - */ - sk_sp<SkColorFilter> mColorSpaceWithFilter; - - /** * Indicates raster data backing the layer is scaled, requiring filtration. */ bool forceFilter = false; diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 80f2b5714659..2a488378e3a8 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -66,13 +66,10 @@ CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBi sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace())); - sk_sp<SkColorFilter> colorSpaceFilter; - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), kPremul_SkAlphaType); - return copyImageInto(image, colorSpaceFilter, texTransform, srcRect, bitmap); + reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), + kPremul_SkAlphaType, colorSpace); + return copyImageInto(image, texTransform, srcRect, bitmap); } CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { @@ -83,20 +80,7 @@ CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { transform.loadScale(1, -1, 1); transform.translate(0, -1); - // TODO: Try to take and reuse the image inside HW bitmap with "hwBitmap->makeImage". - // TODO: When this was attempted, it resulted in instability. - sk_sp<SkColorFilter> colorSpaceFilter; - sk_sp<SkColorSpace> colorSpace = hwBitmap->info().refColorSpace(); - if (colorSpace && !colorSpace->isSRGB()) { - colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); - } - sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(hwBitmap->graphicBuffer()), kPremul_SkAlphaType); - - // HW Bitmap currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 format - // and SRGB color space. ImageDecoder can create a new HW Bitmap with non-SRGB color space: for - // example see android.graphics.cts.BitmapColorSpaceTest#testEncodeP3hardware test. - return copyImageInto(image, colorSpaceFilter, transform, srcRect, bitmap); + return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap); } CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { @@ -118,8 +102,7 @@ CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap return copyResult; } -CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, - sk_sp<SkColorFilter>& colorSpaceFilter, Matrix4& texTransform, +CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { mRenderThread.requireGlContext(); @@ -157,11 +140,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, return copyResult; } - // See Readback::copyLayerInto for an overview of color space conversion. - // HW Bitmap are allowed to be in a non-SRGB color space (for example coming from ImageDecoder). - // For Surface and HW Bitmap readback flows we pass colorSpaceFilter, which does the conversion. - // TextureView readback is using Layer::setDataSpace, which creates a SkColorFilter internally. - Layer layer(mRenderThread.renderState(), colorSpaceFilter, 255, SkBlendMode::kSrc); + Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc); bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); layer.setForceFilter(!disableFilter); @@ -177,38 +156,6 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap) { - /* - * In the past only TextureView readback was setting the temporary surface color space to null. - * Now all 3 readback flows are drawing into a SkSurface with null color space. - * At readback there are 3 options to convert the source image color space to the destination - * color space requested in "bitmap->info().colorSpace()": - * 1. Set color space for temporary surface render target to null (disables color management), - * colorspace tag from source SkImage is ignored by Skia, - * convert SkImage to SRGB at draw time with SkColorFilter/SkToSRGBColorFilter, - * do a readback from temporary SkSurface to a temporary SRGB SkBitmap "bitmap2", - * read back from SRGB "bitmap2" into non-SRGB "bitmap" which will do a CPU color conversion. - * - * 2. Set color space for temporary surface render target to SRGB (not nullptr), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to SRGB at draw time with drawImage (no filters), - * do a readback from temporary SkSurface, which will do a color conversion from SRGB to - * bitmap->info().colorSpace() on the CPU. - * - * 3. Set color space for temporary surface render target to bitmap->info().colorSpace(), - * colorspace tag on the source SkImage is used by Skia to enable conversion, - * convert SkImage to bitmap->info().colorSpace() at draw time with drawImage (no filters), - * do a readback from SkSurface, which will not do any color conversion, because - * surface was created with the same color space as the "bitmap". - * - * Option 1 is used for all readback flows. - * Options 2 and 3 are new, because skia added support for non-SRGB render targets without - * linear blending. - * TODO: evaluate if options 2 or 3 for color space conversion are better. - */ - - // drop the colorSpace from the temporary surface. - SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr); - /* This intermediate surface is present to work around a bug in SwiftShader that * prevents us from reading the contents of the layer's texture directly. The * workaround involves first rendering that texture into an intermediate buffer and @@ -217,70 +164,44 @@ bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* * with reading incorrect data from EGLImage backed SkImage (likely a driver bug). */ sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), - SkBudgeted::kYes, surfaceInfo); + SkBudgeted::kYes, bitmap->info()); + // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we + // attempt to do the intermediate rendering step in 8888 if (!tmpSurface.get()) { - surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType); + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, - surfaceInfo); + tmpInfo); if (!tmpSurface.get()) { - ALOGW("Unable to readback GPU contents into the provided bitmap"); + ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap"); return false; } } - if (skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), - tmpSurface->getCanvas(), layer, srcRect, dstRect, - false)) { - // If bitmap->info().colorSpace() is non-SRGB, convert the data from SRGB to non-SRGB on - // CPU. We can't just pass bitmap->info() to SkSurface::readPixels, because "tmpSurface" has - // disabled color conversion. - SkColorSpace* destColorSpace = bitmap->info().colorSpace(); - SkBitmap tempSRGBBitmap; - SkBitmap tmpN32Bitmap; - SkBitmap* bitmapInSRGB; - if (destColorSpace && !destColorSpace->isSRGB()) { - tempSRGBBitmap.allocPixels(bitmap->info().makeColorSpace(SkColorSpace::MakeSRGB())); - bitmapInSRGB = &tempSRGBBitmap; // Need to convert latter from SRGB to non-SRGB. - } else { - bitmapInSRGB = bitmap; // No need for color conversion - write directly into output. - } - bool success = false; - - // TODO: does any of the readbacks below clamp F16 exSRGB? - // Readback into a SRGB SkBitmap. - if (tmpSurface->readPixels(bitmapInSRGB->info(), bitmapInSRGB->getPixels(), - bitmapInSRGB->rowBytes(), 0, 0)) { - success = true; - } else { - // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into - // 8888 and then convert that into the destination format before giving up. - SkImageInfo bitmapInfo = - SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType(), - SkColorSpace::MakeSRGB()); - if (tmpN32Bitmap.tryAllocPixels(bitmapInfo) && - tmpSurface->readPixels(bitmapInfo, tmpN32Bitmap.getPixels(), - tmpN32Bitmap.rowBytes(), 0, 0)) { - success = true; - bitmapInSRGB = &tmpN32Bitmap; - } - } - - if (success) { - if (bitmapInSRGB != bitmap) { - // Convert from SRGB to non-SRGB color space if needed. Convert from N32 to - // destination bitmap color format if needed. - if (!bitmapInSRGB->readPixels(bitmap->info(), bitmap->getPixels(), - bitmap->rowBytes(), 0, 0)) { - return false; - } - } - bitmap->notifyPixelsChanged(); - return true; + if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), + tmpSurface->getCanvas(), layer, srcRect, dstRect, + false)) { + ALOGW("Unable to draw content from GPU into the provided bitmap"); + return false; + } + + if (!tmpSurface->readPixels(*bitmap, 0, 0)) { + // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into + // 8888 and then convert that into the destination format before giving up. + SkBitmap tmpBitmap; + SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType); + if (bitmap->info().colorType() == SkColorType::kN32_SkColorType || + !tmpBitmap.tryAllocPixels(tmpInfo) || + !tmpSurface->readPixels(tmpBitmap, 0, 0) || + !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(), + bitmap->rowBytes(), 0, 0)) { + ALOGW("Unable to convert content into the provided bitmap"); + return false; } } - return false; + bitmap->notifyPixelsChanged(); + return true; } } /* namespace uirenderer */ diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index d9e10cedc0e8..e86a8136cfa3 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -54,8 +54,8 @@ public: CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); private: - CopyResult copyImageInto(const sk_sp<SkImage>& image, sk_sp<SkColorFilter>& colorSpaceFilter, - Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap); + CopyResult copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap); bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, SkBitmap* bitmap); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d2a8f02cc6a7..4a639102192f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -29,6 +29,7 @@ #include <SkPathOps.h> #include <algorithm> +#include <atomic> #include <sstream> #include <string> @@ -47,8 +48,14 @@ private: TreeInfo* mTreeInfo; }; +static int64_t generateId() { + static std::atomic<int64_t> sNextId{1}; + return sNextId++; +} + RenderNode::RenderNode() - : mDirtyPropertyFields(0) + : mUniqueId(generateId()) + , mDirtyPropertyFields(0) , mNeedsDisplayListSync(false) , mDisplayList(nullptr) , mStagingDisplayList(nullptr) @@ -444,5 +451,38 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { return &mClippedOutlineCache.clippedOutline; } +using StringBuffer = FatVector<char, 128>; + +template <typename... T> +static void format(StringBuffer& buffer, const std::string_view& format, T... args) { + buffer.resize(buffer.capacity()); + while (1) { + int needed = snprintf(buffer.data(), buffer.size(), + format.data(), std::forward<T>(args)...); + if (needed < 0) { + buffer[0] = '\0'; + buffer.resize(1); + return; + } + if (needed < buffer.size()) { + buffer.resize(needed + 1); + return; + } + buffer.resize(buffer.size() * 2); + } +} + +void RenderNode::markDrawStart(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + +void RenderNode::markDrawEnd(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "/RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index be0b46b1c45f..6060123ed759 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -213,6 +213,11 @@ public: UsageHint usageHint() const { return mUsageHint; } + int64_t uniqueId() const { return mUniqueId; } + + void markDrawStart(SkCanvas& canvas); + void markDrawEnd(SkCanvas& canvas); + private: void computeOrderingImpl(RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, @@ -233,6 +238,7 @@ private: void incParentRefCount() { mParentCount++; } void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr); + const int64_t mUniqueId; String8 mName; sp<VirtualLightRefBase> mUserContext; diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 9a15ff2de463..ba343841d760 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -27,7 +27,6 @@ #include <SkAnimatedImage.h> #include <SkCanvasStateUtils.h> #include <SkColorFilter.h> -#include <SkColorSpaceXformCanvas.h> #include <SkDeque.h> #include <SkDrawable.h> #include <SkFont.h> @@ -61,19 +60,8 @@ SkiaCanvas::SkiaCanvas() {} SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {} SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - mCanvasOwned = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - if (cs.get() == nullptr || cs->isSRGB()) { - mCanvas = mCanvasOwned.get(); - } else { - /** The wrapper is needed if we are drawing into a non-sRGB destination, since - * we need to transform all colors (not just bitmaps via filters) into the - * destination's colorspace. - */ - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs)); - mCanvas = mCanvasWrapper.get(); - } + mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); } SkiaCanvas::~SkiaCanvas() {} @@ -82,7 +70,6 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { if (mCanvas != skiaCanvas) { mCanvas = skiaCanvas; mCanvasOwned.reset(); - mCanvasWrapper.reset(); } mSaveStack.reset(nullptr); } @@ -92,18 +79,9 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { // ---------------------------------------------------------------------------- void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { - sk_sp<SkColorSpace> cs = bitmap.refColorSpace(); - std::unique_ptr<SkCanvas> newCanvas = - std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); - std::unique_ptr<SkCanvas> newCanvasWrapper; - if (cs.get() != nullptr && !cs->isSRGB()) { - newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); - } - // deletes the previously owned canvas (if any) - mCanvasOwned = std::move(newCanvas); - mCanvasWrapper = std::move(newCanvasWrapper); - mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get(); + mCanvasOwned.reset(new SkCanvas(bitmap)); + mCanvas = mCanvasOwned.get(); // clean up the old save stack mSaveStack.reset(nullptr); @@ -548,40 +526,14 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -SkiaCanvas::PaintCoW&& SkiaCanvas::filterBitmap(PaintCoW&& paint, - sk_sp<SkColorFilter> colorSpaceFilter) const { - /* We don't apply the colorSpace filter if this canvas is already wrapped with - * a SkColorSpaceXformCanvas since it already takes care of converting the - * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper - * should only be used if this canvas is backed by a surface/bitmap that is known - * to have a non-sRGB colorspace. - */ - if (!mCanvasWrapper && colorSpaceFilter) { - SkPaint& tmpPaint = paint.writeable(); - if (tmpPaint.getColorFilter()) { - tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter(tmpPaint.refColorFilter(), - std::move(colorSpaceFilter))); - LOG_ALWAYS_FATAL_IF(!tmpPaint.getColorFilter()); - } else { - tmpPaint.setColorFilter(std::move(colorSpaceFilter)); - } - } - return filterPaint(std::move(paint)); -} - void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint)); } void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, @@ -590,9 +542,7 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float s SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint); } @@ -674,13 +624,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, PaintCoW paintCoW(paint); SkPaint& tmpPaint = paintCoW.writeable(); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - if (colorFilter) { - shader = shader->makeWithColorFilter(std::move(colorFilter)); - } tmpPaint.setShader(std::move(shader)); mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, @@ -711,10 +657,7 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mCanvas->drawImageLattice(image.get(), lattice, dst, - filterBitmap(paint, std::move(colorFilter))); + mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint)); } double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 3a877cf84010..24d9c08ec1c6 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -232,7 +232,6 @@ private: class Clip; - std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us // unless it is the same as mCanvasOwned.get() diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 75a6e722dd8a..6c77f9ee1845 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -32,7 +32,6 @@ #include <SkCanvas.h> #include <SkImagePriv.h> -#include <SkToSRGBColorFilter.h> #include <SkHighContrastFilter.h> #include <limits> @@ -287,14 +286,8 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { void Bitmap::getSkBitmap(SkBitmap* outBitmap) { if (isHardware()) { - outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), - info().colorType(), info().alphaType(), nullptr)); + outBitmap->allocPixels(mInfo); uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap); - if (mInfo.colorSpace()) { - sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef()); - outBitmap->setInfo(mInfo); - outBitmap->setPixelRef(std::move(pixelRef), 0, 0); - } return; } outBitmap->setInfo(mInfo, rowBytes()); @@ -313,7 +306,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { return nullptr; } -sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { +sk_sp<SkImage> Bitmap::makeImage() { sk_sp<SkImage> image = mImage; if (!image) { SkASSERT(!isHardware()); @@ -325,9 +318,6 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); } - if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) { - *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); - } return image; } diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 238c764cdea6..d446377ec1d9 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -105,14 +105,8 @@ public: * Creates or returns a cached SkImage and is safe to be invoked from either * the UI or RenderThread. * - * @param outputColorFilter is a required param that will be populated by - * this function if the bitmap's colorspace is not sRGB. If populated the - * filter will convert colors from the bitmaps colorspace into sRGB. It - * is the callers responsibility to use this colorFilter when drawing - * this image into any destination that is presumed to be sRGB (i.e. a - * buffer that has no colorspace defined). */ - sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter); + sk_sp<SkImage> makeImage(); static BitmapPalette computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 0cd64069bc5c..9b408fbc95ca 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -89,7 +89,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer SkPaint paint; paint.setAlpha(layer->getAlpha()); paint.setBlendMode(layer->getMode()); - paint.setColorFilter(layer->getColorSpaceWithFilter()); + paint.setColorFilter(layer->getColorFilter()); const bool nonIdentityMatrix = !matrix.isIdentity(); if (nonIdentityMatrix) { canvas->save(); diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index ea14d11b7b3e..d80cb6d1ab70 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -115,12 +115,26 @@ void RenderNodeDrawable::onDraw(SkCanvas* canvas) { } } +class MarkDraw { +public: + explicit MarkDraw(SkCanvas& canvas, RenderNode& node) : mCanvas(canvas), mNode(node) { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawStart(mCanvas); + } + } + ~MarkDraw() { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawEnd(mCanvas); + } + } +private: + SkCanvas& mCanvas; + RenderNode& mNode; +}; + void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { RenderNode* renderNode = mRenderNode.get(); - if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { - SkRect dimensions = SkRect::MakeWH(renderNode->getWidth(), renderNode->getHeight()); - canvas->drawAnnotation(dimensions, renderNode->getName(), nullptr); - } + MarkDraw _marker{*canvas, *renderNode}; // We only respect the nothingToDraw check when we are composing a layer. This // ensures that we paint the layer even if it is not currently visible in the diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 6ae59990d0ab..07979a22c988 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -97,7 +97,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con SkASSERT(mRenderThread.getGrContext() != nullptr); sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget( mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType, - nullptr, &props)); + mSurfaceColorSpace, &props)); SkiaPipeline::updateLighting(lightGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); @@ -155,7 +155,7 @@ void SkiaOpenGLPipeline::onStop() { } } -bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, +bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, ColorMode colorMode) { if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); @@ -176,6 +176,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, } else if (colorMode == ColorMode::WideColorGamut) { mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType; } + mSurfaceColorSpace = SkColorSpace::MakeSRGB(); if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 4ab3541d447b..479910697871 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -42,7 +42,7 @@ public: bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; - bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, + bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; void onStop() override; bool isSurfaceReady() override; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 2dfe7c71ca1b..7a255c15bf5f 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -169,7 +169,7 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) { SkImageInfo info; info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(), - kPremul_SkAlphaType); + kPremul_SkAlphaType, getSurfaceColorSpace()); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), @@ -204,8 +204,7 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); - sk_sp<SkColorFilter> colorFilter; - auto image = bitmap->makeImage(&colorFilter); + auto image = bitmap->makeImage(); if (image.get() && !bitmap->isHardware()) { SkImage_pinAsTexture(image.get(), context); SkImage_unpinAsTexture(image.get(), context); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 45022e733979..f5de1c8adfaf 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -179,9 +179,8 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, } void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, left, top, filterPaint(paint), bitmap.palette()); // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means // it is not safe to store a raw SkImage pointer, because the image object will be destroyed // when this function ends. @@ -194,9 +193,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImage(image, 0, 0, filterPaint(paint), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } @@ -208,9 +206,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); - mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), + sk_sp<SkImage> image = bitmap.makeImage(); + mRecorder.drawImageRect(image, srcRect, dstRect, filterPaint(paint), SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { @@ -247,10 +244,9 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) { filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); mRecorder.drawImageLattice(image, lattice, dst, - filterBitmap(std::move(filteredPaint), std::move(colorFilter)), + filterPaint(std::move(filteredPaint)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index a494e490aea1..e50ad1cd8c44 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -115,7 +115,7 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { void SkiaVulkanPipeline::onStop() {} -bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, +bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, ColorMode colorMode) { if (mVkSurface) { mVkManager.destroySurface(mVkSurface); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 14c0d69dba33..02874c7d2c69 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -38,7 +38,7 @@ public: bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; - bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, + bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; void onStop() override; bool isSurfaceReady() override; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f1a522ecd588..182233fb3715 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -142,7 +142,12 @@ void CanvasContext::destroy() { void CanvasContext::setSurface(sp<Surface>&& surface) { ATRACE_CALL(); - mNativeSurface = std::move(surface); + if (surface) { + mNativeSurface = new ReliableSurface{std::move(surface)}; + mNativeSurface->setDequeueTimeout(500_ms); + } else { + mNativeSurface = nullptr; + } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); @@ -285,6 +290,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy info.damageAccumulator = &mDamageAccumulator; info.layerUpdateQueue = &mLayerUpdateQueue; + info.out.canDrawThisFrame = true; mAnimationContext->startFrame(info.mode); mRenderPipeline->onPrepareTree(); @@ -304,7 +310,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy mIsDirty = true; - if (CC_UNLIKELY(!mNativeSurface.get())) { + if (CC_UNLIKELY(!hasSurface())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); info.out.canDrawThisFrame = false; return; @@ -323,27 +329,6 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // the deadline for RT animations info.out.canDrawThisFrame = false; } - /* This logic exists to try and recover from a display latch miss, which essentially - * results in the bufferqueue being double-buffered instead of triple-buffered. - * SurfaceFlinger itself now tries to handle & recover from this situation, so this - * logic should no longer be necessary. As it's occasionally triggering when - * undesired disable it. - * TODO: Remove this entirely if the results are solid. - else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 || - (latestVsync - mLastDropVsync) < 500_ms) { - // It's been several frame intervals, assume the buffer queue is fine - // or the last drop was too recent - info.out.canDrawThisFrame = true; - } else { - info.out.canDrawThisFrame = !isSwapChainStuffed(); - if (!info.out.canDrawThisFrame) { - // dropping frame - mLastDropVsync = mRenderThread.timeLord().latestVsync(); - } - } - */ - } else { - info.out.canDrawThisFrame = true; } // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even @@ -354,6 +339,19 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy if (!info.out.canDrawThisFrame) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + return; + } + + int err = mNativeSurface->reserveNext(); + if (err != OK) { + mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + info.out.canDrawThisFrame = false; + ALOGW("reserveNext failed, error = %d", err); + if (err != TIMED_OUT) { + // A timed out surface can still recover, but assume others are permanently dead. + setSurface(nullptr); + } + return; } bool postedFrameCallback = false; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 70be4a6d7730..9e7abf447cd6 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -25,6 +25,7 @@ #include "IRenderPipeline.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" +#include "ReliableSurface.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include "thread/Task.h" @@ -219,7 +220,7 @@ private: EGLint mLastFrameHeight = 0; RenderThread& mRenderThread; - sp<Surface> mNativeSurface; + sp<ReliableSurface> mNativeSurface; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 65ced6ad9316..8230dfd44f9a 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -31,6 +31,8 @@ #include <string> #include <vector> +#include <system/window.h> +#include <gui/Surface.h> #define GLES_VERSION 2 @@ -106,7 +108,7 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE, "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString()); - ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor); + ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor); initExtensions(); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 4972554c65cc..42e17b273bee 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -28,9 +28,9 @@ class GrContext; -namespace android { +struct ANativeWindow; -class Surface; +namespace android { namespace uirenderer { @@ -67,7 +67,7 @@ public: virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; - virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; + virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; virtual void onStop() = 0; virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp new file mode 100644 index 000000000000..0ab4cd29f1cd --- /dev/null +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ReliableSurface.h" + +#include <private/android/AHardwareBufferHelpers.h> + +namespace android::uirenderer::renderthread { + +// TODO: Make surface less protected +// This exists because perform is a varargs, and ANativeWindow has no va_list perform. +// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do +// that instead +struct SurfaceExposer : Surface { + // Make warnings happy + SurfaceExposer() = delete; + + using Surface::setBufferCount; + using Surface::setSwapInterval; + using Surface::dequeueBuffer; + using Surface::queueBuffer; + using Surface::cancelBuffer; + using Surface::lockBuffer_DEPRECATED; + using Surface::perform; +}; + +#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) + +ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) { + LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr"); + + ANativeWindow::setSwapInterval = hook_setSwapInterval; + ANativeWindow::dequeueBuffer = hook_dequeueBuffer; + ANativeWindow::cancelBuffer = hook_cancelBuffer; + ANativeWindow::queueBuffer = hook_queueBuffer; + ANativeWindow::query = hook_query; + ANativeWindow::perform = hook_perform; + + ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; + ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; +} + +void ReliableSurface::perform(int operation, va_list args) { + std::lock_guard _lock{mMutex}; + + switch (operation) { + case NATIVE_WINDOW_SET_USAGE: + mUsage = va_arg(args, uint32_t); + break; + case NATIVE_WINDOW_SET_USAGE64: + mUsage = va_arg(args, uint64_t); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + /* width */ va_arg(args, uint32_t); + /* height */ va_arg(args, uint32_t); + mFormat = va_arg(args, PixelFormat); + break; + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + mFormat = va_arg(args, PixelFormat); + break; + } +} + +int ReliableSurface::reserveNext() { + { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + ALOGW("reserveNext called but there was already a buffer reserved?"); + return OK; + } + if (mInErrorState) { + return UNKNOWN_ERROR; + } + } + + int fenceFd = -1; + ANativeWindowBuffer* buffer = nullptr; + int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd); + + { + std::lock_guard _lock{mMutex}; + LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext"); + mReservedBuffer = buffer; + mReservedFenceFd.reset(fenceFd); + if (result != OK) { + ALOGW("reserveNext failed, error %d", result); + } + } + + return result; +} + +void ReliableSurface::clearReservedBuffer() { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + ALOGW("Reserved buffer %p was never used", mReservedBuffer); + } + mReservedBuffer = nullptr; + mReservedFenceFd.reset(); +} + +int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) { + clearReservedBuffer(); + if (isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } + int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd); + return result; +} + +int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) { + { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + *buffer = mReservedBuffer; + *fenceFd = mReservedFenceFd.release(); + mReservedBuffer = nullptr; + return OK; + } + } + + int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd); + if (result != OK) { + ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); + *buffer = acquireFallbackBuffer(); + *fenceFd = -1; + return *buffer ? OK : INVALID_OPERATION; + } + return OK; +} + +int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) { + clearReservedBuffer(); + + if (isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } + + int result = callProtected(mSurface, queueBuffer, buffer, fenceFd); + return result; +} + +bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const { + if (!mScratchBuffer || !windowBuffer) { + return false; + } + ANativeWindowBuffer* scratchBuffer = + AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); + return windowBuffer == scratchBuffer; +} + +ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() { + std::lock_guard _lock{mMutex}; + mInErrorState = true; + + if (mScratchBuffer) { + return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); + } + + AHardwareBuffer_Desc desc; + desc.usage = mUsage; + desc.format = mFormat; + desc.width = 1; + desc.height = 1; + desc.layers = 1; + desc.rfu0 = 0; + desc.rfu1 = 0; + AHardwareBuffer* newBuffer = nullptr; + int err = AHardwareBuffer_allocate(&desc, &newBuffer); + if (err) { + // Allocate failed, that sucks + ALOGW("Failed to allocate scratch buffer, error=%d", err); + return nullptr; + } + mScratchBuffer.reset(newBuffer); + return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer); +} + +Surface* ReliableSurface::getWrapped(const ANativeWindow* window) { + return getSelf(window)->mSurface.get(); +} + +int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) { + return callProtected(getWrapped(window), setSwapInterval, interval); +} + +int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, + int* fenceFd) { + return getSelf(window)->dequeueBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, + int fenceFd) { + return getSelf(window)->cancelBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, + int fenceFd) { + return getSelf(window)->queueBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer) { + ANativeWindowBuffer* buf; + int fenceFd = -1; + int result = window->dequeueBuffer(window, &buf, &fenceFd); + if (result != OK) { + return result; + } + sp<Fence> fence(new Fence(fenceFd)); + int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); + if (waitResult != OK) { + ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult); + window->cancelBuffer(window, buf, -1); + return waitResult; + } + *buffer = buf; + return result; +} + +int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + return window->cancelBuffer(window, buffer, -1); +} + +int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + // This method is a no-op in Surface as well + return OK; +} + +int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + return window->queueBuffer(window, buffer, -1); +} + +int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) { + return getWrapped(window)->query(what, value); +} + +int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { + va_list args; + va_start(args, operation); + int result = callProtected(getWrapped(window), perform, operation, args); + va_end(args); + + switch (operation) { + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + case NATIVE_WINDOW_SET_USAGE: + case NATIVE_WINDOW_SET_USAGE64: + va_start(args, operation); + getSelf(window)->perform(operation, args); + va_end(args); + break; + default: + break; + } + + return result; +} + +}; // namespace android::uirenderer::renderthread
\ No newline at end of file diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h new file mode 100644 index 000000000000..9ae53a9798d3 --- /dev/null +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gui/Surface.h> +#include <utils/Macros.h> +#include <utils/StrongPointer.h> + +#include <memory> + +namespace android::uirenderer::renderthread { + +class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> { + PREVENT_COPY_AND_ASSIGN(ReliableSurface); + +public: + ReliableSurface(sp<Surface>&& surface); + + void setDequeueTimeout(nsecs_t timeout) { mSurface->setDequeueTimeout(timeout); } + + int reserveNext(); + + void allocateBuffers() { mSurface->allocateBuffers(); } + + int query(int what, int* value) const { return mSurface->query(what, value); } + + nsecs_t getLastDequeueStartTime() const { return mSurface->getLastDequeueStartTime(); } + + uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); } + +private: + const sp<Surface> mSurface; + + mutable std::mutex mMutex; + + uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + PixelFormat mFormat = PIXEL_FORMAT_RGBA_8888; + std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{ + nullptr, AHardwareBuffer_release}; + bool mInErrorState = false; + ANativeWindowBuffer* mReservedBuffer = nullptr; + base::unique_fd mReservedFenceFd; + + bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const; + ANativeWindowBuffer* acquireFallbackBuffer(); + void clearReservedBuffer(); + + void perform(int operation, va_list args); + int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); + int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); + int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); + + static Surface* getWrapped(const ANativeWindow*); + + // ANativeWindow hooks + static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, + int* fenceFd); + static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + + static int hook_perform(ANativeWindow* window, int operation, ...); + static int hook_query(const ANativeWindow* window, int what, int* value); + static int hook_setSwapInterval(ANativeWindow* window, int interval); + + static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); + static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); +}; + +}; // namespace android::uirenderer::renderthread
\ No newline at end of file diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp index 9ffccfb4d340..15aec9f291a4 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -22,6 +22,7 @@ #include "renderthread/EglManager.h" #include "renderthread/RenderThread.h" #include "renderthread/VulkanManager.h" +#include "utils/Color.h" // Macro for including the SurfaceTexture name in log messages #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) @@ -44,13 +45,16 @@ void ImageConsumer::onReleaseBufferLocked(int buf) { mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR; } -void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) { - if (!mImage.get()) { +void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer, + android_dataspace dataspace) { + if (!mImage.get() || dataspace != mDataspace) { mImage = graphicBuffer.get() ? SkImage::MakeFromAHardwareBuffer( reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), - kPremul_SkAlphaType) + kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace)) : nullptr; + mDataspace = dataspace; } } @@ -66,7 +70,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, int slot = st.mCurrentTexture; if (slot != BufferItem::INVALID_BUFFER_SLOT) { *queueEmpty = true; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } } @@ -145,7 +149,7 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, st.computeCurrentTransformMatrixLocked(); *queueEmpty = false; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace); return mImageSlots[slot].mImage; } diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h index 31ee8db52874..5bab0ef58a9a 100644 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -68,18 +68,21 @@ private: * ImageConsumer maintains about a BufferQueue buffer slot. */ struct ImageSlot { - ImageSlot() : mEglFence(EGL_NO_SYNC_KHR) {} + ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {} // mImage is the SkImage created from mGraphicBuffer. sk_sp<SkImage> mImage; + // the dataspace associated with the current image + android_dataspace mDataspace; + /** * mEglFence is the EGL sync object that must signal before the buffer * associated with this buffer slot may be dequeued. */ EGLSyncKHR mEglFence; - void createIfNeeded(sp<GraphicBuffer> graphicBuffer); + void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace); }; /** diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp index 4bff715822e8..90f891265572 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -470,8 +470,7 @@ void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { ConsumerBase::dumpLocked(result, prefix); } -sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, +sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, uirenderer::RenderState& renderState) { Mutex::Autolock _l(mMutex); @@ -488,7 +487,6 @@ sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_d auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); if (image.get()) { uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); - dataSpace = mCurrentDataSpace; } return image; } diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h index db392a9f8476..96afd82b0d40 100644 --- a/libs/hwui/surfacetexture/SurfaceTexture.h +++ b/libs/hwui/surfacetexture/SurfaceTexture.h @@ -258,8 +258,8 @@ public: */ status_t attachToContext(uint32_t tex); - sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, - bool* queueEmpty, uirenderer::RenderState& renderState); + sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, + uirenderer::RenderState& renderState); /** * attachToView attaches a SurfaceTexture that is currently in the diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 66b9b85bdbe7..8a1bc4d2f7f2 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -72,9 +72,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( layerUpdater->setTransform(&transform); // updateLayer so it's ready to draw - SkMatrix identity; - identity.setIdentity(); - layerUpdater->updateLayer(true, identity, HAL_DATASPACE_UNKNOWN, nullptr); + layerUpdater->updateLayer(true, SkMatrix::I(), nullptr); return layerUpdater; } diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index 15039b5fa976..ad11a1d32310 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -44,8 +44,7 @@ public: }); SkPaint paint; - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter); + sk_sp<SkImage> image = hwuiBitmap->makeImage(); sk_sp<SkShader> repeatShader = image->makeShader(SkShader::TileMode::kRepeat_TileMode, SkShader::TileMode::kRepeat_TileMode, nullptr); diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index f137562e7c73..448408d19eb1 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -72,8 +72,7 @@ public: void doFrame(int frameNr) override {} sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) { - sk_sp<SkColorFilter> colorFilter; - sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkImage> image = bitmap.makeImage(); return image->makeShader(SkShader::TileMode::kClamp_TileMode, SkShader::TileMode::kClamp_TileMode); } diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp index c235715073f5..210fced574e9 100644 --- a/libs/hwui/tests/unit/CacheManagerTests.cpp +++ b/libs/hwui/tests/unit/CacheManagerTests.cpp @@ -54,8 +54,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) { // create an image and pin it so that we have something with a unique key in the cache sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(displayInfo.w, displayInfo.h)); - sk_sp<SkColorFilter> filter; - sk_sp<SkImage> image = bitmap->makeImage(&filter); + sk_sp<SkImage> image = bitmap->makeImage(); ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext)); // attempt to trim all memory while we still hold strong refs diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index 6c8775b1bdbb..a6869791a915 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -43,7 +43,7 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) { SkBitmap bitmap; bitmap.allocN32Pixels(16, 16); sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap); - layerUpdater->updateLayer(true, scaledMatrix, HAL_DATASPACE_UNKNOWN, layerImage); + layerUpdater->updateLayer(true, scaledMatrix, layerImage); // the backing layer should now have all the properties applied. EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth()); diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 634ceffe0741..f3a764874e2b 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -53,12 +53,12 @@ TEST(SkiaCanvas, colorSpaceXform) { adobeBitmap->getSkBitmap(&adobeSkBitmap); *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red - SkImageInfo info = adobeInfo.makeColorSpace(nullptr); + SkImageInfo info = adobeInfo.makeColorSpace(SkColorSpace::MakeSRGB()); sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info); SkBitmap skBitmap; bitmap->getSkBitmap(&skBitmap); - // Create a software canvas. + // Create a software sRGB canvas. SkiaCanvas canvas(skBitmap); canvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); // The result should be fully red, since we convert to sRGB at draw time. @@ -77,7 +77,7 @@ TEST(SkiaCanvas, colorSpaceXform) { picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - // Playback to an software canvas. The result should be fully red. + // Playback to a software sRGB canvas. The result should be fully red. canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h index f60c338bf9c4..8de2ab49f42b 100644 --- a/libs/services/include/android/os/StatsLogEventWrapper.h +++ b/libs/services/include/android/os/StatsLogEventWrapper.h @@ -82,6 +82,11 @@ struct StatsLogValue { STATS_LOG_VALUE_TYPE type; }; +struct WorkChain { + std::vector<int32_t> uids; + std::vector<std::string> tags; +}; + // Represents a parcelable object. Only used to send data from Android OS to statsd. class StatsLogEventWrapper : public android::Parcelable { public: @@ -99,7 +104,9 @@ class StatsLogEventWrapper : public android::Parcelable { int64_t getWallClockTimeNs() const { return mWallClockTimeNs; } - std::vector<StatsLogValue> getElements() const { return mElements; } + const std::vector<StatsLogValue>& getElements() const { return mElements; } + + const std::vector<WorkChain>& getWorkChains() const { return mWorkChains; } private: int mTagId; @@ -109,6 +116,8 @@ class StatsLogEventWrapper : public android::Parcelable { int64_t mWallClockTimeNs; std::vector<StatsLogValue> mElements; + + std::vector<WorkChain> mWorkChains; }; } // Namespace os } // Namespace android diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp index 04c4629b5432..f6dfdef16e19 100644 --- a/libs/services/src/os/StatsLogEventWrapper.cpp +++ b/libs/services/src/os/StatsLogEventWrapper.cpp @@ -58,6 +58,31 @@ status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) { ALOGE("statsd could not read wall clock time from parcel"); return res; } + int numWorkChain = 0; + if ((res = in->readInt32(&numWorkChain)) != OK) { + ALOGE("statsd could not read number of work chains from parcel"); + return res; + } + if (numWorkChain > 0) { + for (int i = 0; i < numWorkChain; i++) { + int numNodes = 0; + if ((res = in->readInt32(&numNodes)) != OK) { + ALOGE( + "statsd could not read number of nodes in work chain from parcel"); + return res; + } + if (numNodes == 0) { + ALOGE("empty work chain"); + return BAD_VALUE; + } + WorkChain wc; + for (int j = 0; j < numNodes; j++) { + wc.uids.push_back(in->readInt32()); + wc.tags.push_back(std::string(String8(in->readString16()).string())); + } + mWorkChains.push_back(wc); + } + } int dataSize = 0; if ((res = in->readInt32(&dataSize)) != OK) { ALOGE("statsd could not read data size from parcel"); |