diff options
Diffstat (limited to 'libs')
47 files changed, 540 insertions, 241 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 5667f9283241..ab7e14de48fb 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -533,8 +533,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Create the max possible entries we can make. Once we construct the bag, // we will realloc to fit to size. const size_t max_count = parent_bag->entry_count + dtohl(map->count); - ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>( - malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry)))); + util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( + malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))}; ResolvedBag::Entry* new_entry = new_bag->entries; const ResolvedBag::Entry* parent_entry = parent_bag->entries; @@ -601,15 +601,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { // Resize the resulting array to fit. const size_t actual_count = new_entry - new_bag->entries; if (actual_count != max_count) { - new_bag = reinterpret_cast<ResolvedBag*>( - realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))); + new_bag.reset(reinterpret_cast<ResolvedBag*>(realloc( + new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))))); } - util::unique_cptr<ResolvedBag> final_bag{new_bag}; - final_bag->type_spec_flags = flags; - final_bag->entry_count = static_cast<uint32_t>(actual_count); - ResolvedBag* result = final_bag.get(); - cached_bags_[resid] = std::move(final_bag); + new_bag->type_spec_flags = flags; + new_bag->entry_count = static_cast<uint32_t>(actual_count); + ResolvedBag* result = new_bag.get(); + cached_bags_[resid] = std::move(new_bag); return result; } diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index c19c1a11e3e2..8727a1d20dfd 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -296,6 +296,7 @@ void GlopBuilder::setFill(int color, float alphaScale, colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f); colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear } else { + ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName()); LOG_ALWAYS_FATAL("unsupported ColorFilter"); } } else { diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index acc75393ebcf..fe291d2a4bfe 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -51,6 +51,7 @@ int Properties::overrideSpotShadowStrength = -1; ProfileType Properties::sProfileType = ProfileType::None; bool Properties::sDisableProfileBars = false; RenderPipelineType Properties::sRenderPipelineType = RenderPipelineType::NotInitialized; +bool Properties::enableHighContrastText = false; bool Properties::waitForGpuCompletion = false; bool Properties::forceDrawFrame = false; diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 47ae9e912127..0fe4c7714761 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -17,6 +17,7 @@ #ifndef ANDROID_HWUI_PROPERTIES_H #define ANDROID_HWUI_PROPERTIES_H +#include <cutils/compiler.h> #include <cutils/properties.h> /** @@ -237,6 +238,8 @@ public: static RenderPipelineType getRenderPipelineType(); static bool isSkiaEnabled(); + ANDROID_API static bool enableHighContrastText; + // Should be used only by test apps static bool waitForGpuCompletion; static bool forceDrawFrame; diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index ccdb4b0c1d8e..79db496f2acd 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -93,11 +93,6 @@ public: virtual int width() override { return mState.getWidth(); } virtual int height() override { return mState.getHeight(); } - virtual void setHighContrastText(bool highContrastText) override { - mHighContrastText = highContrastText; - } - virtual bool isHighContrastText() override { return mHighContrastText; } - // ---------------------------------------------------------------------------- // android/graphics/Canvas state operations // ---------------------------------------------------------------------------- @@ -311,7 +306,6 @@ private: DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None; const ClipBase* mDeferredBarrierClip = nullptr; DisplayList* mDisplayList = nullptr; - bool mHighContrastText = false; sk_sp<SkDrawFilter> mDrawFilter; }; // class RecordingCanvas diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 61b3876cd095..36a747519c37 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -32,6 +32,7 @@ #include "protos/hwui.pb.h" #include "protos/ProtoHelpers.h" +#include <SkPathOps.h> #include <algorithm> #include <sstream> #include <string> @@ -555,5 +556,23 @@ void RenderNode::computeOrderingImpl( } } +const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { + const SkPath* outlinePath = properties().getOutline().getPath(); + const uint32_t outlineID = outlinePath->getGenerationID(); + + if (outlineID != mClippedOutlineCache.outlineID || clipRect != mClippedOutlineCache.clipRect) { + // update the cache keys + mClippedOutlineCache.outlineID = outlineID; + mClippedOutlineCache.clipRect = clipRect; + + // update the cache value by recomputing a new path + SkPath clipPath; + clipPath.addRect(clipRect); + Op(*outlinePath, clipPath, kIntersect_SkPathOp, &mClippedOutlineCache.clippedOutline); + + } + return &mClippedOutlineCache.clippedOutline; +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index c4ae82af430c..89e022f5e68d 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -365,6 +365,17 @@ public: return mSkiaLayer.get(); } + /** + * Returns the path that represents the outline of RenderNode intersected with + * the provided rect. This call will internally cache the resulting path in + * order to potentially return that path for subsequent calls to this method. + * By reusing the same path we get better performance on the GPU backends since + * those resources are cached in the hardware based on the path's genID. + * + * The returned path is only guaranteed to be valid until this function is called + * again or the RenderNode's outline is mutated. + */ + const SkPath* getClippedOutline(const SkRect& clipRect) const; private: /** * If this RenderNode has been used in a previous frame then the SkiaDisplayList @@ -380,6 +391,16 @@ private: * when it has been set to draw as a LayerType::RenderLayer. */ std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer; + + struct ClippedOutlineCache { + // keys + uint32_t outlineID = 0; + SkRect clipRect; + + // value + SkPath clippedOutline; + }; + mutable ClippedOutlineCache mClippedOutlineCache; }; // class RenderNode class MarkAndSweepRemoved : public TreeObserver { diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 0a642b60d4c7..1f5f733188de 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -24,6 +24,7 @@ #include "pipeline/skia/AnimatedDrawables.h" #include <SkCanvasStateUtils.h> +#include <SkColorFilter.h> #include <SkColorSpaceXformCanvas.h> #include <SkDrawable.h> #include <SkDeque.h> @@ -46,25 +47,33 @@ Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { return new SkiaCanvas(bitmap); } -Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB) { - return new SkiaCanvas(skiaCanvas, xformToSRGB); +Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { + return new SkiaCanvas(skiaCanvas); } SkiaCanvas::SkiaCanvas() {} -SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB) - : mCanvas(canvas) -{ - LOG_ALWAYS_FATAL_IF(XformToSRGB::kImmediate == xformToSRGB); -} +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)); - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), - cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); - mCanvas = mCanvasWrapper.get(); + if (cs.get() == nullptr || cs->isSRGB()) { + if(!uirenderer::Properties::isSkiaEnabled()) { + mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB()); + mCanvas = mCanvasWrapper.get(); + } else { + 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(); + } } SkiaCanvas::~SkiaCanvas() {} @@ -73,9 +82,9 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) { if (mCanvas != skiaCanvas) { mCanvas = skiaCanvas; mCanvasOwned.reset(); + mCanvasWrapper.reset(); } mSaveStack.reset(nullptr); - mHighContrastText = false; } // ---------------------------------------------------------------------------- @@ -86,13 +95,18 @@ 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 = SkCreateColorSpaceXformCanvas(newCanvas.get(), - cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); + std::unique_ptr<SkCanvas> newCanvasWrapper; + if (cs.get() != nullptr && !cs->isSRGB()) { + newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); + } + else if(!uirenderer::Properties::isSkiaEnabled()) { + newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB()); + } // deletes the previously owned canvas (if any) mCanvasOwned = std::move(newCanvas); mCanvasWrapper = std::move(newCanvasWrapper); - mCanvas = mCanvasWrapper.get(); + mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get(); // clean up the old save stack mSaveStack.reset(nullptr); @@ -518,6 +532,9 @@ void SkiaCanvas::drawArc(float left, float top, float right, float bottom, void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { if (CC_UNLIKELY(paint.nothingToDraw())) return; + if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) { + return; + } mCanvas->drawPath(path, paint); } @@ -529,25 +546,64 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons // Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- +const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorSpaceFilter) { + /* 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) { + if (origPaint) { + *tmpPaint = *origPaint; + } + + if (tmpPaint->getColorFilter()) { + tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter( + tmpPaint->refColorFilter(), colorSpaceFilter)); + LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter()); + } else { + tmpPaint->setColorFilter(colorSpaceFilter); + } + + return tmpPaint; + } else { + return origPaint; + } +} + void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - mCanvas->drawImage(bitmap.makeImage(), left, top, paint); + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) { +void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(mCanvas, true); mCanvas->concat(matrix); - mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter)); } -void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, +void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter), + SkCanvas::kFast_SrcRectConstraint); } -void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight, +void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, const float* vertices, const int* colors, const SkPaint* paint) { const int ptCount = (meshWidth + 1) * (meshHeight + 1); const int indexCount = meshWidth * meshHeight * 6; @@ -565,8 +621,8 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh // cons up texture coordinates and indices { - const SkScalar w = SkIntToScalar(hwuiBitmap.width()); - const SkScalar h = SkIntToScalar(hwuiBitmap.height()); + const SkScalar w = SkIntToScalar(bitmap.width()); + const SkScalar h = SkIntToScalar(bitmap.height()); const SkScalar dx = w / meshWidth; const SkScalar dy = h / meshHeight; @@ -627,17 +683,22 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh tmpPaint = *paint; } - sk_sp<SkImage> image = hwuiBitmap.makeImage(); - tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); + if(colorFilter) { + shader = shader->makeWithColorFilter(colorFilter); + } + tmpPaint.setShader(shader); mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint); } -void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, +void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkCanvas::Lattice lattice; - NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height()); + NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); lattice.fFlags = nullptr; int numFlags = 0; @@ -654,7 +715,11 @@ void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint); + + SkPaint tmpPaint; + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter)); } void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index af2c23e4a2b7..e17f835031bb 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -37,12 +37,8 @@ public: * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must * not be NULL. This constructor does not take ownership, so the caller * must guarantee that it remains valid while the SkiaCanvas is valid. - * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB - * color space before drawing. This makes sense for software rendering. - * For the picture case, it may make more sense to leave bitmaps as is, - * and handle the xform when replaying the picture. */ - explicit SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB); + explicit SkiaCanvas(SkCanvas* canvas); virtual ~SkiaCanvas(); @@ -69,11 +65,6 @@ public: virtual int width() override; virtual int height() override; - virtual void setHighContrastText(bool highContrastText) override { - mHighContrastText = highContrastText; - } - virtual bool isHighContrastText() override { return mHighContrastText; } - virtual int getSaveCount() const override; virtual int save(SaveFlags::Flags flags) override; virtual void restore() override; @@ -170,8 +161,6 @@ private: size_t clipIndex; }; - bool mHighContrastText = false; - const SaveRec* currentSaveRec() const; void recordPartialSave(SaveFlags::Flags flags); @@ -182,6 +171,9 @@ private: void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode); + const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorSpaceFilter); + class Clip; std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp index 16a19ca4d36a..ddddefac74b9 100644 --- a/libs/hwui/SkiaCanvasProxy.cpp +++ b/libs/hwui/SkiaCanvasProxy.cpp @@ -179,7 +179,7 @@ void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& la SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kFast_SrcRectConstraint); } } @@ -452,7 +452,7 @@ void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala break; } default: - SkFAIL("unhandled positioning mode"); + SK_ABORT("unhandled positioning mode"); } } } diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 8a1de02e6a0c..f4ce864e83e1 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -565,7 +565,7 @@ void Tree::draw(SkCanvas* canvas) { sk_sp<SkSurface> vdSurface = mCache.getSurface(&src); if (vdSurface) { canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, - mutateProperties()->getBounds(), getPaint()); + mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint); } else { // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure. // We render the VD into a temporary standalone buffer and mark the frame as dirty. Next @@ -585,7 +585,7 @@ void Tree::draw(SkCanvas* canvas) { draw(surface.get(), src); mCache.clear(); canvas->drawImageRect(surface->makeImageSnapshot().get(), mutateProperties()->getBounds(), - getPaint()); + getPaint(), SkCanvas::kFast_SrcRectConstraint); markDirty(); } } diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 75b6d233643d..0aeb7627233a 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -31,6 +31,7 @@ #include <ui/PixelFormat.h> #include <SkCanvas.h> +#include <SkToSRGBColorFilter.h> #include <SkImagePriv.h> namespace android { @@ -208,11 +209,8 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info) buffer->incStrong(buffer); setImmutable(); // HW bitmaps are always immutable if (uirenderer::Properties::isSkiaEnabled()) { - // GraphicBuffer should be in the display color space (Bitmap::createFrom is always - // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if - // needed. mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer), - mInfo.alphaType(), nullptr); + mInfo.alphaType(), mInfo.refColorSpace()); } } @@ -319,7 +317,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { return nullptr; } -sk_sp<SkImage> Bitmap::makeImage() { +sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { sk_sp<SkImage> image = mImage; if (!image) { SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled())); @@ -330,12 +328,11 @@ sk_sp<SkImage> Bitmap::makeImage() { // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap // internally and ~Bitmap won't be invoked. // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. - if (uirenderer::Properties::isSkiaEnabled()) { - image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(), - skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode); - } else { - image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); - } + image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); + } + if(uirenderer::Properties::isSkiaEnabled() && 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 634e76450c38..fc27af9fb4e7 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -16,6 +16,7 @@ #pragma once #include <SkBitmap.h> +#include <SkColorFilter.h> #include <SkColorSpace.h> #include <SkImage.h> #include <SkImageInfo.h> @@ -96,9 +97,18 @@ public: GraphicBuffer* graphicBuffer(); - // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread. - // Caching is supported only for HW Bitmaps with skia pipeline. - sk_sp<SkImage> makeImage(); + /** + * 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); private: virtual ~Bitmap(); void* getStorage() const; diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index e754daf7c42e..a087035fd8e5 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -158,7 +158,7 @@ private: }; void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, - float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) { + float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface) { // minikin may modify the original paint Paint paint(origPaint); @@ -207,7 +207,7 @@ private: }; void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, - float hOffset, float vOffset, const Paint& paint, Typeface* typeface) { + float hOffset, float vOffset, const Paint& paint, const Typeface* typeface) { Paint paintCopy(paint); minikin::Layout layout = MinikinUtils::doLayout( &paintCopy, bidiFlags, typeface, text, 0, count, count); diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index ac8a08169997..fbd89606fc9d 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -20,6 +20,7 @@ #include <utils/Functor.h> #include "GlFunctorLifecycleListener.h" +#include "Properties.h" #include "utils/Macros.h" #include <androidfw/ResourceTypes.h> @@ -98,15 +99,6 @@ public: static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode = nullptr); - enum class XformToSRGB { - // Transform any Bitmaps to the sRGB color space before drawing. - kImmediate, - - // Draw the Bitmap as is. This likely means that we are recording and that the - // transform can be handled at playback time. - kDefer, - }; - /** * Create a new Canvas object which delegates to an SkCanvas. * @@ -114,12 +106,10 @@ public: * delegated to this object. This function will call ref() on the * SkCanvas, and the returned Canvas will unref() it upon * destruction. - * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB - * color space before drawing. * @return new non-null Canvas Object. The type of DisplayList produced by this canvas is * determined based on Properties::getRenderPipelineType(). */ - static Canvas* create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB); + static Canvas* create_canvas(SkCanvas* skiaCanvas); /** * Provides a Skia SkCanvas interface that acts as a proxy to this Canvas. @@ -151,8 +141,7 @@ public: virtual uirenderer::DisplayList* finishRecording() = 0; virtual void insertReorderBarrier(bool enableReorder) = 0; - virtual void setHighContrastText(bool highContrastText) = 0; - virtual bool isHighContrastText() = 0; + bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; } virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, @@ -266,10 +255,10 @@ public: * and delegating the final draw to virtual drawGlyphs method. */ void drawText(const uint16_t* text, int start, int count, int contextCount, - float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface); + float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface); void drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, - float hOffset, float vOffset, const Paint& paint, Typeface* typeface); + float hOffset, float vOffset, const Paint& paint, const Typeface* typeface); protected: void drawTextDecorations(float x, float y, float length, const SkPaint& paint); diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index ba4e3a4df578..2b29542fb623 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -67,6 +67,17 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, bounds->mBottom = skBounds.fBottom; } +void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent, + const minikin::MinikinPaint& paint) const { + SkPaint skPaint; + MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint); + SkPaint::FontMetrics metrics; + skPaint.getFontMetrics(&metrics); + extent->ascent = metrics.fAscent; + extent->descent = metrics.fDescent; + extent->line_gap = metrics.fLeading; +} + SkTypeface *MinikinFontSkia::GetSkTypeface() const { return mTypeface.get(); } diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h index 6c12485845fd..a19f4a769444 100644 --- a/libs/hwui/hwui/MinikinSkia.h +++ b/libs/hwui/hwui/MinikinSkia.h @@ -37,6 +37,9 @@ public: void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, const minikin::MinikinPaint &paint) const; + void GetFontExtent(minikin::MinikinExtent* extent, + const minikin::MinikinPaint &paint) const; + SkTypeface* GetSkTypeface() const; sk_sp<SkTypeface> RefSkTypeface() const; diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 415eef77f44e..7da7f3876a3d 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -27,7 +27,7 @@ namespace android { minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, - const Paint* paint, Typeface* typeface) { + const Paint* paint, const Typeface* typeface) { const Typeface* resolvedFace = Typeface::resolveDefault(typeface); minikin::FontStyle resolved = resolvedFace->fStyle; @@ -39,10 +39,8 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini resolved.getItalic()); /* Prepare minikin Paint */ - // Note: it would be nice to handle fractional size values (it would improve smooth zoom - // behavior), but historically size has been treated as an int. - // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set. - minikinPaint->size = (int)paint->getTextSize(); + minikinPaint->size = paint->isLinearText() ? + paint->getTextSize() : static_cast<int>(paint->getTextSize()); minikinPaint->scaleX = paint->getTextScaleX(); minikinPaint->skewX = paint->getTextSkewX(); minikinPaint->letterSpacing = paint->getLetterSpacing(); @@ -54,7 +52,7 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini } minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags, - Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize) { minikin::MinikinPaint minikinPaint; minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface); @@ -64,16 +62,17 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags, return layout; } -float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface, +float MinikinUtils::measureText(const Paint* paint, int bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) { minikin::MinikinPaint minikinPaint; minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface); - Typeface* resolvedTypeface = Typeface::resolveDefault(typeface); + const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface); return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, - minikinPaint, resolvedTypeface->fFontCollection, advances); + minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */, + nullptr /* overhangs */); } -bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) { +bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) { const Typeface* resolvedFace = Typeface::resolveDefault(typeface); return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs); } diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 0f22adc5d42b..bfd816fd3b58 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -35,16 +35,17 @@ namespace android { class MinikinUtils { public: ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, - const Paint* paint, Typeface* typeface); + const Paint* paint, const Typeface* typeface); ANDROID_API static minikin::Layout doLayout(const Paint* paint, int bidiFlags, - Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize); - ANDROID_API static float measureText(const Paint* paint, int bidiFlags, Typeface* typeface, - const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances); + ANDROID_API static float measureText(const Paint* paint, int bidiFlags, + const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, + size_t bufSize, float *advances); - ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint, + ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs); ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index a5d83a0ca018..f3779fddb620 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GRAPHICS_PAINT_H_ #define ANDROID_GRAPHICS_PAINT_H_ +#include "Typeface.h" + #include <cutils/compiler.h> #include <SkPaint.h> @@ -101,6 +103,14 @@ public: return mHyphenEdit; } + void setAndroidTypeface(Typeface* typeface) { + mTypeface = typeface; + } + + const Typeface* getAndroidTypeface() const { + return mTypeface; + } + private: float mLetterSpacing = 0; float mWordSpacing = 0; @@ -108,6 +118,10 @@ private: uint32_t mMinikinLangListId; minikin::FontVariant mFontVariant; uint32_t mHyphenEdit = 0; + // The native Typeface object has the same lifetime of the Java Typeface object. The Java Paint + // object holds a strong reference to the Java Typeface object. Thus, following pointer can + // never be a dangling pointer. Note that nullptr is valid: it means the default typeface. + const Typeface* mTypeface = nullptr; }; } // namespace android diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp index 67427433bb89..a5c2087490aa 100644 --- a/libs/hwui/hwui/PaintImpl.cpp +++ b/libs/hwui/hwui/PaintImpl.cpp @@ -27,7 +27,8 @@ Paint::Paint(const Paint& paint) : SkPaint(paint), mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant), - mHyphenEdit(paint.mHyphenEdit) { + mHyphenEdit(paint.mHyphenEdit), + mTypeface(paint.mTypeface) { } Paint::Paint(const SkPaint& paint) : SkPaint(paint), @@ -46,6 +47,7 @@ Paint& Paint::operator=(const Paint& other) { mMinikinLangListId = other.mMinikinLangListId; mFontVariant = other.mFontVariant; mHyphenEdit = other.mHyphenEdit; + mTypeface = other.mTypeface; return *this; } @@ -56,7 +58,8 @@ bool operator==(const Paint& a, const Paint& b) { && a.mFontFeatureSettings == b.mFontFeatureSettings && a.mMinikinLangListId == b.mMinikinLangListId && a.mFontVariant == b.mFontVariant - && a.mHyphenEdit == b.mHyphenEdit; + && a.mHyphenEdit == b.mHyphenEdit + && a.mTypeface == b.mTypeface; } } diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index f66bb045373c..0a388745b14c 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -14,12 +14,6 @@ * limitations under the License. */ -/** - * This is the implementation of the Typeface object. Historically, it has - * just been SkTypeface, but we are migrating to Minikin. For the time - * being, that choice is hidden under the USE_MINIKIN compile-time flag. - */ - #include "Typeface.h" #include <pthread.h> @@ -65,15 +59,15 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style return computeMinikinStyle(weight, italic); } -Typeface* gDefaultTypeface = NULL; +const Typeface* gDefaultTypeface = NULL; -Typeface* Typeface::resolveDefault(Typeface* src) { - LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr); +const Typeface* Typeface::resolveDefault(const Typeface* src) { + LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr); return src == nullptr ? gDefaultTypeface : src; } Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -85,7 +79,7 @@ Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) { } Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) { - Typeface* resolvedFace = Typeface::resolveDefault(base); + const Typeface* resolvedFace = Typeface::resolveDefault(base); Typeface* result = new Typeface(); if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -98,7 +92,7 @@ Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) { Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, const std::vector<minikin::FontVariation>& variations) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface(); if (result != nullptr) { result->fFontCollection = @@ -118,7 +112,7 @@ Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, } Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) { - Typeface* resolvedFace = Typeface::resolveDefault(src); + const Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; @@ -172,7 +166,7 @@ Typeface* Typeface::createFromFamilies( return result; } -void Typeface::setDefault(Typeface* face) { +void Typeface::setDefault(const Typeface* face) { gDefaultTypeface = face; } diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index db0b2cdeba00..38c623480196 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -41,7 +41,7 @@ struct ANDROID_API Typeface { // style used for constructing and querying Typeface objects SkTypeface::Style fSkiaStyle; - static Typeface* resolveDefault(Typeface* src); + static const Typeface* resolveDefault(const Typeface* src); // The following three functions create new Typeface from an existing Typeface with a different // style. There is a base weight concept which is used for calculating relative style from an @@ -78,7 +78,7 @@ struct ANDROID_API Typeface { std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic); - static void setDefault(Typeface* face); + static void setDefault(const Typeface* face); // Sets roboto font as the default typeface for testing purpose. static void setRobotoTypefaceForTest(); diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index ea302a154616..fcd72afe4fb9 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -17,6 +17,7 @@ #include "GLFunctorDrawable.h" #include "GlFunctorLifecycleListener.h" #include "RenderNode.h" +#include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" #include <private/hwui/DrawGlInfo.h> #include <GrContext.h> @@ -49,8 +50,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { return; } - canvas->flush(); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { canvas->clear(SK_ColorRED); return; @@ -72,33 +71,33 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { info.height = canvasInfo.height(); mat4.asColMajorf(&info.transform[0]); + bool clearStencilAfterFunctor = false; + //apply a simple clip with a scissor or a complex clip with a stencil SkRegion clipRegion; canvas->temporary_internal_getRgnClip(&clipRegion); if (CC_UNLIKELY(clipRegion.isComplex())) { - //It is only a temporary solution to use a scissor to draw the stencil. - //There is a bug 31489986 to implement efficiently non-rectangular clips. glDisable(GL_SCISSOR_TEST); - glDisable(GL_STENCIL_TEST); - glStencilMask(0xff); + glStencilMask(0x1); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); - glEnable(GL_SCISSOR_TEST); - SkRegion::Cliperator it(clipRegion, ibounds); - while (!it.done()) { - setScissor(info.height, it.rect()); - glClearStencil(0x1); - glClear(GL_STENCIL_BUFFER_BIT); - it.next(); + bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas); + canvas->flush(); + if (stencilWritten) { + glStencilMask(0x1); + glStencilFunc(GL_EQUAL, 0x1, 0x1); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + clearStencilAfterFunctor = true; + glEnable(GL_STENCIL_TEST); + } else { + glDisable(GL_STENCIL_TEST); } - glDisable(GL_SCISSOR_TEST); - glStencilFunc(GL_EQUAL, 0x1, 0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glEnable(GL_STENCIL_TEST); } else if (clipRegion.isEmpty()) { + canvas->flush(); glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); } else { + canvas->flush(); glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); setScissor(info.height, clipRegion.getBounds()); @@ -106,6 +105,15 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (clearStencilAfterFunctor) { + //clear stencil buffer as it may be used by Skia + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glStencilMask(0x1); + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + } + canvas->getGrContext()->resetContext(); } diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 4feeb2d6facb..17438e5e1cdc 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -28,7 +28,10 @@ namespace uirenderer { namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { - DrawLayer(canvas->getGrContext(), canvas, mLayer.get()); + Layer* layer = mLayerUpdater->backingLayer(); + if (layer) { + DrawLayer(canvas->getGrContext(), canvas, layer); + } } bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 431989519a70..d34d8e07c133 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -16,7 +16,7 @@ #pragma once -#include "Layer.h" +#include "DeferredLayerUpdater.h" #include <SkCanvas.h> #include <SkDrawable.h> @@ -30,18 +30,18 @@ namespace skiapipeline { */ class LayerDrawable : public SkDrawable { public: - explicit LayerDrawable(Layer* layer) - : mLayer(layer) {} + explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) + : mLayerUpdater(layerUpdater) {} static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer); protected: virtual SkRect onGetBounds() override { - return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight()); + return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight()); } virtual void onDraw(SkCanvas* canvas) override; private: - sp<Layer> mLayer; + sp<DeferredLayerUpdater> mLayerUpdater; }; }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp index 374d364787de..c8207bc70dd4 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp @@ -163,28 +163,22 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* hwuiMatrix.copyTo(shadowMatrix); canvas->concat(shadowMatrix); - const SkPath* casterOutlinePath = casterProperties.getOutline().getPath(); - // holds temporary SkPath to store the result of intersections - SkPath tmpPath; - const SkPath* casterPath = casterOutlinePath; + // default the shadow-casting path to the outline of the caster + const SkPath* casterPath = casterProperties.getOutline().getPath(); + + // intersect the shadow-casting path with the clipBounds, if present + if (clippedToBounds && !casterClipRect.contains(casterPath->getBounds())) { + casterPath = caster->getRenderNode()->getClippedOutline(casterClipRect); + } - // TODO: In to following course of code that calculates the final shape, is there an optimal - // of doing the Op calculations? // intersect the shadow-casting path with the reveal, if present + SkPath tmpPath; // holds temporary SkPath to store the result of intersections if (revealClipPath) { Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath); tmpPath.setIsVolatile(true); casterPath = &tmpPath; } - // intersect the shadow-casting path with the clipBounds, if present - if (clippedToBounds) { - SkPath clipBoundsPath; - clipBoundsPath.addRect(casterClipRect); - Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath); - tmpPath.setIsVolatile(true); - casterPath = &tmpPath; - } const Vector3 lightPos = SkiaPipeline::getLightCenter(); SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z); SkPoint3 zParams; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 925db303461f..abba70e4bdd5 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -73,9 +73,11 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, // setup surface for fbo0 GrGLFramebufferInfo fboInfo; fboInfo.fFBOID = 0; + GrPixelConfig pixelConfig = + wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig; GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, - kRGBA_8888_GrPixelConfig, fboInfo); + pixelConfig, fboInfo); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); @@ -132,9 +134,24 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi deferredLayer->updateTexImage(); deferredLayer->apply(); - SkCanvas canvas(*bitmap); + /* 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 + * then reading from the intermediate buffer into the bitmap. + */ + sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), + SkBudgeted::kYes, bitmap->info()); + Layer* layer = deferredLayer->backingLayer(); - return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer); + if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) { + sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot(); + if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { + bitmap->notifyPixelsChanged(); + return true; + } + } + + return false; } static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, @@ -303,12 +320,6 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr return nullptr; } - auto colorSpace = info.colorSpace(); - bool convertToSRGB = false; - if (colorSpace && (!colorSpace->isSRGB())) { - isSupported = false; - convertToSRGB = true; - } SkBitmap bitmap; if (isSupported) { @@ -317,7 +328,7 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); bitmap.eraseColor(0); - if (info.colorType() == kRGBA_F16_SkColorType || convertToSRGB) { + if (info.colorType() == kRGBA_F16_SkColorType) { // Drawing RGBA_F16 onto ARGB_8888 is not supported skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), bitmap.getPixels(), bitmap.rowBytes(), 0, 0); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp index 311419dd2b65..9982a0cfe2bf 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -16,6 +16,7 @@ #include "SkiaOpenGLReadback.h" +#include "DeviceInfo.h" #include "Matrix.h" #include "Properties.h" #include <SkCanvas.h> @@ -54,28 +55,60 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; externalTexture.fID = sourceTexId; - GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture); + GrPixelConfig pixelConfig; + switch (bitmap->colorType()) { + case kRGBA_F16_SkColorType: + pixelConfig = kRGBA_half_GrPixelConfig; + break; + case kN32_SkColorType: + default: + pixelConfig = kRGBA_8888_GrPixelConfig; + break; + } + + /* Ideally, we would call grContext->caps()->isConfigRenderable(...). We + * currently can't do that since some devices (i.e. SwiftShader) supports all + * the appropriate half float extensions, but only allow the buffer to be read + * back as full floats. We can relax this extension if Skia implements support + * for reading back float buffers (skbug.com/6945). + */ + if (pixelConfig == kRGBA_half_GrPixelConfig && + !DeviceInfo::get()->extensions().hasFloatTextures()) { + ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); + return CopyResult::DestinationInvalid; + } + + GrBackendTexture backendTexture(imgWidth, imgHeight, pixelConfig, externalTexture); CopyResult copyResult = CopyResult::UnknownError; sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin)); if (image) { + // Convert imgTransform matrix from right to left handed coordinate system. + // If we have a matrix transformation in right handed coordinate system + //|ScaleX, SkewX, TransX| same transform in left handed is |ScaleX, SkewX, TransX | + //|SkewY, ScaleY, TransY| |-SkewY, -ScaleY, 1-TransY| + //|0, 0, 1 | |0, 0, 1 | SkMatrix textureMatrix; - imgTransform.copyTo(textureMatrix); - - // remove the y-flip applied to the matrix - SkMatrix yFlip = SkMatrix::MakeScale(1, -1); - yFlip.postTranslate(0,1); - textureMatrix.preConcat(yFlip); - - // multiply by image size, because textureMatrix maps to [0..1] range - textureMatrix[SkMatrix::kMTransX] *= imgWidth; - textureMatrix[SkMatrix::kMTransY] *= imgHeight; - - // swap rotation and translation part of the matrix, because we convert from - // right-handed Cartesian to left-handed coordinate system. - std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]); - std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]); + textureMatrix.setIdentity(); + textureMatrix[SkMatrix::kMScaleX] = imgTransform[Matrix4::kScaleX]; + textureMatrix[SkMatrix::kMScaleY] = -imgTransform[Matrix4::kScaleY]; + textureMatrix[SkMatrix::kMSkewX] = imgTransform[Matrix4::kSkewX]; + textureMatrix[SkMatrix::kMSkewY] = -imgTransform[Matrix4::kSkewY]; + textureMatrix[SkMatrix::kMTransX] = imgTransform[Matrix4::kTranslateX]; + textureMatrix[SkMatrix::kMTransY] = 1-imgTransform[Matrix4::kTranslateY]; + + // textureMatrix maps 2D texture coordinates of the form (s, t, 1) with s and t in the + // inclusive range [0, 1] to the texture (see GLConsumer::getTransformMatrix comments). + // Convert textureMatrix to translate in real texture dimensions. Texture width and + // height are affected by the orientation (width and height swapped for 90/270 rotation). + if (textureMatrix[SkMatrix::kMSkewX] >= 0.5f || textureMatrix[SkMatrix::kMSkewX] <= -0.5f) { + textureMatrix[SkMatrix::kMTransX] *= imgHeight; + textureMatrix[SkMatrix::kMTransY] *= imgWidth; + } else { + textureMatrix[SkMatrix::kMTransX] *= imgWidth; + textureMatrix[SkMatrix::kMTransY] *= imgHeight; + } // convert to Skia data structures SkRect skiaSrcRect = srcRect.toSkRect(); @@ -103,7 +136,8 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); scaledSurface->getCanvas()->concat(textureMatrix); - scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint); + scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint, + SkCanvas::kFast_SrcRectConstraint); image = scaledSurface->makeImageSnapshot(); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 03792e0ed291..a8463ecc44d8 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -134,7 +134,13 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut) { SkSurface* layer = node->getLayerSurface(); if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) { - SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); + SkImageInfo info; + if (wideColorGamut) { + info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType, + kPremul_SkAlphaType); + } else { + info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); + } SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); // TODO: Handle wide color gamut requests @@ -161,7 +167,8 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height()); - auto image = bitmap->makeImage(); + sk_sp<SkColorFilter> colorFilter; + auto image = bitmap->makeImage(&colorFilter); 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 a0cce98c8d57..0bdf15333647 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -91,10 +91,9 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { } void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { - if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) { - uirenderer::Layer* layer = layerUpdater->backingLayer(); + if (layerUpdater != nullptr) { // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL. - sk_sp<SkDrawable> drawable(new LayerDrawable(layer)); + sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater)); drawDrawable(drawable.get()); } } @@ -145,10 +144,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { // Recording Canvas draw operations: Bitmaps // ---------------------------------------------------------------------------- -inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) { - if (origPaint && origPaint->isAntiAlias()) { - *tmpPaint = *origPaint; +inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint, + sk_sp<SkColorFilter> colorFilter) { + if ((origPaint && origPaint->isAntiAlias()) || colorFilter) { + if (origPaint) { + *tmpPaint = *origPaint; + } + + sk_sp<SkColorFilter> filter; + if (colorFilter && tmpPaint->getColorFilter()) { + filter = SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorFilter); + LOG_ALWAYS_FATAL_IF(!filter); + } else { + filter = colorFilter; + } + tmpPaint->setAntiAlias(false); + tmpPaint->setColorFilter(filter); return tmpPaint; } else { return origPaint; @@ -156,9 +168,10 @@ inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPa } void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - sk_sp<SkImage> image = bitmap.makeImage(); SkPaint tmpPaint; - mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint)); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter)); // 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. @@ -167,36 +180,41 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons } } -void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, +void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { SkAutoCanvasRestore acr(&mRecorder, true); concat(matrix); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); + SkPaint tmpPaint; - mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) { + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter)); + if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } } -void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, +void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); + SkPaint tmpPaint; - mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter), + SkCanvas::kFast_SrcRectConstraint); + if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); } } -void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, +void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { SkCanvas::Lattice lattice; - NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height()); + NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); lattice.fFlags = nullptr; int numFlags = 0; @@ -213,11 +231,13 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch lattice.fBounds = nullptr; SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); - sk_sp<SkImage> image = hwuiBitmap.makeImage(); SkPaint tmpPaint; - mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint)); - if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); + mRecorder.drawImageLattice(image.get(), lattice, dst, + bitmapPaint(paint, &tmpPaint, colorFilter)); + if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); } } diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp index 437653a8dfa8..23969908ff4d 100644 --- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp +++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp @@ -21,6 +21,7 @@ #include <cmath> #include "utils/TraceUtils.h" #include "renderthread/RenderProxy.h" +#include "renderthread/RenderThread.h" namespace android { namespace uirenderer { @@ -228,6 +229,15 @@ AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) { void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) { if (INVALID_ATLAS_KEY != atlasKey) { + if (!renderthread::RenderThread::isCurrent()) { + { + AutoMutex _lock(mReleaseKeyLock); + mKeysForRelease.push_back(atlasKey); + } + // invoke releaseEntry on the renderthread + renderthread::RenderProxy::releaseVDAtlasEntries(); + return; + } CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey); if (!entry->surface) { // Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas @@ -245,6 +255,14 @@ void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) { } } +void VectorDrawableAtlas::delayedReleaseEntries() { + AutoMutex _lock(mReleaseKeyLock); + for (auto key : mKeysForRelease) { + releaseEntry(key); + } + mKeysForRelease.clear(); +} + sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) { #ifndef ANDROID_ENABLE_LINEAR_BLENDING sk_sp<SkColorSpace> colorSpace = nullptr; diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h index 496c55742748..0683b3915850 100644 --- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h +++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h @@ -20,6 +20,7 @@ #include <SkSurface.h> #include <utils/FatVector.h> #include <utils/RefBase.h> +#include <utils/Thread.h> #include <list> class GrRectanizer; @@ -103,12 +104,19 @@ public: /** * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey" - * is causing an undefined behaviour. + * is causing an undefined behaviour. This is the only function in the class that can be + * invoked from any thread. It will marshal internally to render thread if needed. */ void releaseEntry(AtlasKey atlasKey); void setStorageMode(StorageMode mode); + /** + * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is + * invoked from a non render thread. + */ + void delayedReleaseEntries(); + private: struct CacheEntry { CacheEntry(const SkRect& newVDrect, const SkRect& newRect, @@ -182,6 +190,17 @@ private: */ StorageMode mStorageMode; + /** + * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary + * calling thread to the render thread. + */ + std::vector<AtlasKey> mKeysForRelease; + + /** + * A lock used to protect access to mKeysForRelease. + */ + Mutex mReleaseKeyLock; + sk_sp<SkSurface> createSurface(int width, int height, GrContext* context); inline bool fitInAtlas(int width, int height) { diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 55694d046c2f..f6b23e1a0723 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -44,7 +44,7 @@ namespace renderthread { CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) { mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2, - skiapipeline::VectorDrawableAtlas::StorageMode::allowSharedSurface); + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); } void CacheManager::reset(GrContext* context) { @@ -62,7 +62,8 @@ void CacheManager::reset(GrContext* context) { void CacheManager::destroy() { // cleanup any caches here as the GrContext is about to go away... mGrContext.reset(nullptr); - mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2); + mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2, + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); } void CacheManager::updateContextCacheSizes() { diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 16d77364942e..87e5bfdc8ca5 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -138,7 +138,7 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL_IF(!glInterface.get()); GrContextOptions options; - options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField; + options.fDisableDistanceFieldPaths = true; mRenderThread.cacheManager().configureContext(&options); mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend, (GrBackendContext)glInterface.get(), options)); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 7fe966dde316..690474376bef 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -732,6 +732,18 @@ void RenderProxy::repackVectorDrawableAtlas() { thread.queue(task); } +CREATE_BRIDGE1(releaseVDAtlasEntries, RenderThread* thread) { + args->thread->cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries(); + return nullptr; +} + +void RenderProxy::releaseVDAtlasEntries() { + RenderThread& thread = RenderThread::getInstance(); + SETUP_TASK(releaseVDAtlasEntries); + args->thread = &thread; + thread.queue(task); +} + void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) { void* retval; task->setReturnPtr(&retval); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 06eaebd066ee..9440b15f6062 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -143,6 +143,8 @@ public: static void repackVectorDrawableAtlas(); + static void releaseVDAtlasEntries(); + private: RenderThread& mRenderThread; CanvasContext* mContext; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 72a428f1c70c..51e937485fab 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -499,6 +499,10 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { return nullptr; } +bool RenderThread::isCurrent() { + return gettid() == getInstance().getTid(); +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index bef47b3e27c5..30884b571b94 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -111,6 +111,14 @@ public: sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap); void dumpGraphicsMemory(int fd); + /** + * isCurrent provides a way to query, if the caller is running on + * the render thread. + * + * @return true only if isCurrent is invoked from the render thread. + */ + static bool isCurrent(); + protected: virtual bool threadLoop() override; diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index 4797dec8e89e..0f2dc034d125 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -46,7 +46,8 @@ public: }); SkPaint paint; - sk_sp<SkImage> image = hwuiBitmap->makeImage(); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter); sk_sp<SkShader> repeatShader = image->makeShader( SkShader::TileMode::kRepeat_TileMode, SkShader::TileMode::kRepeat_TileMode, diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp index c246ebaddcad..960b05340063 100644 --- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp +++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp @@ -75,7 +75,8 @@ public: void doFrame(int frameNr) override { } sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) { - sk_sp<SkImage> image = bitmap.makeImage(); + sk_sp<SkColorFilter> colorFilter; + sk_sp<SkImage> image = bitmap.makeImage(&colorFilter); return image->makeShader(SkShader::TileMode::kClamp_TileMode, SkShader::TileMode::kClamp_TileMode); } diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index f166c5ceb974..3089447cbfc5 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -171,7 +171,6 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) { while (benchState.KeepRunning()) { canvas->resetRecording(200, 200); - canvas->setHighContrastText(false); canvas->translate(0, 0); // mScrollX, mScrollY // Clip to padding diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index d36bca031a87..c4e419591a4d 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -822,8 +822,8 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) { } OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) { + Properties::enableHighContrastText = true; auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.setHighContrastText(true); Paint paint; paint.setColor(SK_ColorWHITE); paint.setAntiAlias(true); @@ -832,6 +832,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) { std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO"); canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL); }); + Properties::enableHighContrastText = false; int count = 0; playbackOps(*dl, [&count](const RecordedOp& op) { diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index c048dda4a2e9..d84b83d3f2dc 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -45,8 +45,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { // record the same text draw into a SkPicture and replay it into a Recording canvas SkPictureRecorder recorder; SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0); - std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas, - Canvas::XformToSRGB::kDefer)); + std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas)); TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); @@ -65,7 +64,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { TEST(SkiaCanvas, drawShadowLayer) { auto surface = SkSurface::MakeRasterN32Premul(10, 10); - SkiaCanvas canvas(surface->getCanvas(), Canvas::XformToSRGB::kDefer); + SkiaCanvas canvas(surface->getCanvas()); // clear to white canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc); @@ -108,27 +107,14 @@ TEST(SkiaCanvas, colorSpaceXform) { // The result should be less than fully red, since we convert to Adobe RGB at draw time. ASSERT_EQ(0xFF0000DC, *adobeSkBitmap.getAddr32(0, 0)); - // Now try in kDefer mode. This is a little strange given that, in practice, all software - // canvases are kImmediate. - SkCanvas skCanvas(skBitmap); - SkiaCanvas deferCanvas(&skCanvas, Canvas::XformToSRGB::kDefer); - deferCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); - // The result should be as before, since we deferred the conversion to sRGB. - ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0)); - - // Test picture recording. We will kDefer the xform at recording time, but handle it when - // we playback to the software canvas. + // Test picture recording. SkPictureRecorder recorder; SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0); - SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer); + SkiaCanvas picCanvas(skPicCanvas); picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - // Playback to a deferred canvas. The result should be as before. - deferCanvas.asSkCanvas()->drawPicture(picture); - ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0)); - - // Playback to an immediate canvas. The result should be fully red. + // Playback to an software canvas. The result should be fully red. canvas.asSkCanvas()->drawPicture(picture); ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0)); } @@ -155,7 +141,7 @@ TEST(SkiaCanvas, captureCanvasState) { // Create a picture canvas. SkPictureRecorder recorder; SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0); - SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer); + SkiaCanvas picCanvas(skPicCanvas); state = picCanvas.captureCanvasState(); // Verify that we cannot get the CanvasState. diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index c90b6f0e9cdd..345cfd647b11 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -70,7 +70,8 @@ TEST(TypefaceTest, resolveDefault_and_setDefaultTest) { RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get())); - Typeface* old = Typeface::resolveDefault(nullptr); // Keep the original to restore it later. + // Keep the original to restore it later. + const Typeface* old = Typeface::resolveDefault(nullptr); ASSERT_NE(nullptr, old); Typeface::setDefault(regular.get()); diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto index ae5af0e4afa7..5fd75d6f2809 100644 --- a/libs/incident/proto/android/privacy.proto +++ b/libs/incident/proto/android/privacy.proto @@ -36,7 +36,7 @@ enum Destination { // off the device with an explicit user action. DEST_EXPLICIT = 1; - // Fields or messages annotated with DEST_LOCAL can be sent by + // Fields or messages annotated with DEST_AUTOMATIC can be sent by // automatic means, without per-sending user consent. The user // still must have previously accepted a consent to share this // information. @@ -47,8 +47,11 @@ enum Destination { message PrivacyFlags { optional Destination dest = 1 [ - default = DEST_LOCAL + default = DEST_EXPLICIT ]; + + // regex to filter pii sensitive info from a string field type + repeated string patterns = 2; } extend google.protobuf.FieldOptions { diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto new file mode 100644 index 000000000000..d268cf4fc09a --- /dev/null +++ b/libs/incident/proto/android/section.proto @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 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. + */ + +syntax = "proto2"; + +option java_package = "android"; +option java_multiple_files = true; + +import "google/protobuf/descriptor.proto"; + +package android; + +// SectionType defines how incidentd gonna get the field's data +enum SectionType { + + // Default fields, not available in incidentd + SECTION_NONE = 0; + + // incidentd reads a file to get the data for annotated field + SECTION_FILE = 1; + + // incidentd executes the given command for annotated field + SECTION_COMMAND = 2; + + // incidentd calls dumpsys for annotated field + SECTION_DUMPSYS = 3; +} + +message SectionFlags { + optional SectionType type = 1 [default = SECTION_NONE]; + optional string args = 2; +} + +extend google.protobuf.FieldOptions { + // Flags for automatically section list generation + optional SectionFlags section = 155792027; +} |