summaryrefslogtreecommitdiff
path: root/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
committerXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
commit628590d7ec80e10a3fc24b1c18a1afb55cca10a8 (patch)
tree4b1c3f52d86d7fb53afbe9e9438468588fa489f8 /libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
parentb11b8ec3aec8bb42f2c07e1c5ac7942da293baa8 (diff)
parentd2d3a20624d968199353ccf6ddbae6f3ac39c9af (diff)
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507 Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27 Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
Diffstat (limited to 'libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp')
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp283
1 files changed, 0 insertions, 283 deletions
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
deleted file mode 100644
index e783f389feb8..000000000000
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * 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.
- */
-
-#include "VectorDrawableAtlas.h"
-
-#include <GrRectanizer_pow2.h>
-#include <SkCanvas.h>
-#include <cmath>
-#include "renderthread/RenderProxy.h"
-#include "renderthread/RenderThread.h"
-#include "utils/TraceUtils.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-VectorDrawableAtlas::VectorDrawableAtlas(size_t surfaceArea, StorageMode storageMode)
- : mWidth((int)std::sqrt(surfaceArea))
- , mHeight((int)std::sqrt(surfaceArea))
- , mStorageMode(storageMode) {}
-
-void VectorDrawableAtlas::prepareForDraw(GrContext* context) {
- if (StorageMode::allowSharedSurface == mStorageMode) {
- if (!mSurface) {
- mSurface = createSurface(mWidth, mHeight, context);
- mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
- mPixelUsedByVDs = 0;
- mPixelAllocated = 0;
- mConsecutiveFailures = 0;
- mFreeRects.clear();
- } else {
- if (isFragmented()) {
- // Invoke repack outside renderFrame to avoid jank.
- renderthread::RenderProxy::repackVectorDrawableAtlas();
- }
- }
- }
-}
-
-#define MAX_CONSECUTIVE_FAILURES 5
-#define MAX_UNUSED_RATIO 2.0f
-
-bool VectorDrawableAtlas::isFragmented() {
- return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES &&
- mPixelUsedByVDs * MAX_UNUSED_RATIO < mPixelAllocated;
-}
-
-void VectorDrawableAtlas::repackIfNeeded(GrContext* context) {
- // We repackage when atlas failed to allocate space MAX_CONSECUTIVE_FAILURES consecutive
- // times and the atlas allocated pixels are at least MAX_UNUSED_RATIO times higher than pixels
- // used by atlas VDs.
- if (isFragmented() && mSurface) {
- repack(context);
- }
-}
-
-// compare to CacheEntry objects based on VD area.
-bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second) {
- return first.VDrect.width() * first.VDrect.height() <
- second.VDrect.width() * second.VDrect.height();
-}
-
-void VectorDrawableAtlas::repack(GrContext* context) {
- ATRACE_CALL();
- sk_sp<SkSurface> newSurface;
- SkCanvas* canvas = nullptr;
- if (StorageMode::allowSharedSurface == mStorageMode) {
- newSurface = createSurface(mWidth, mHeight, context);
- if (!newSurface) {
- return;
- }
- canvas = newSurface->getCanvas();
- canvas->clear(SK_ColorTRANSPARENT);
- mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
- } else {
- if (!mSurface) {
- return; // nothing to repack
- }
- mRectanizer.reset();
- }
- mFreeRects.clear();
- SkImage* sourceImageAtlas = nullptr;
- if (mSurface) {
- sourceImageAtlas = mSurface->makeImageSnapshot().get();
- }
-
- // Sort the list by VD size, which allows for the smallest VDs to get first in the atlas.
- // Sorting is safe, because it does not affect iterator validity.
- if (mRects.size() <= 100) {
- mRects.sort(compareCacheEntry);
- }
-
- for (CacheEntry& entry : mRects) {
- SkRect currentVDRect = entry.VDrect;
- SkImage* sourceImage; // copy either from the atlas or from a standalone surface
- if (entry.surface) {
- if (!fitInAtlas(currentVDRect.width(), currentVDRect.height())) {
- continue; // don't even try to repack huge VD
- }
- sourceImage = entry.surface->makeImageSnapshot().get();
- } else {
- sourceImage = sourceImageAtlas;
- }
- size_t VDRectArea = currentVDRect.width() * currentVDRect.height();
- SkIPoint16 pos;
- if (canvas && mRectanizer->addRect(currentVDRect.width(), currentVDRect.height(), &pos)) {
- SkRect newRect =
- SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(), currentVDRect.height());
- canvas->drawImageRect(sourceImage, currentVDRect, newRect, nullptr);
- entry.VDrect = newRect;
- entry.rect = newRect;
- if (entry.surface) {
- // A rectangle moved from a standalone surface to the atlas.
- entry.surface = nullptr;
- mPixelUsedByVDs += VDRectArea;
- }
- } else {
- // Repack failed for this item. If it is not already, store it in a standalone
- // surface.
- if (!entry.surface) {
- // A rectangle moved from an atlas to a standalone surface.
- mPixelUsedByVDs -= VDRectArea;
- SkRect newRect = SkRect::MakeWH(currentVDRect.width(), currentVDRect.height());
- entry.surface = createSurface(newRect.width(), newRect.height(), context);
- auto tempCanvas = entry.surface->getCanvas();
- tempCanvas->clear(SK_ColorTRANSPARENT);
- tempCanvas->drawImageRect(sourceImageAtlas, currentVDRect, newRect, nullptr);
- entry.VDrect = newRect;
- entry.rect = newRect;
- }
- }
- }
- mPixelAllocated = mPixelUsedByVDs;
- context->flush();
- mSurface = newSurface;
- mConsecutiveFailures = 0;
-}
-
-AtlasEntry VectorDrawableAtlas::requestNewEntry(int width, int height, GrContext* context) {
- AtlasEntry result;
- if (width <= 0 || height <= 0) {
- return result;
- }
-
- if (mSurface) {
- const size_t area = width * height;
-
- // Use a rectanizer to allocate unused space from the atlas surface.
- bool notTooBig = fitInAtlas(width, height);
- SkIPoint16 pos;
- if (notTooBig && mRectanizer->addRect(width, height, &pos)) {
- mPixelUsedByVDs += area;
- mPixelAllocated += area;
- result.rect = SkRect::MakeXYWH(pos.fX, pos.fY, width, height);
- result.surface = mSurface;
- auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, nullptr);
- CacheEntry* entry = &(*eraseIt);
- entry->eraseIt = eraseIt;
- result.key = reinterpret_cast<AtlasKey>(entry);
- mConsecutiveFailures = 0;
- return result;
- }
-
- // Try to reuse atlas memory from rectangles freed by "releaseEntry".
- auto freeRectIt = mFreeRects.lower_bound(area);
- while (freeRectIt != mFreeRects.end()) {
- SkRect& freeRect = freeRectIt->second;
- if (freeRect.width() >= width && freeRect.height() >= height) {
- result.rect = SkRect::MakeXYWH(freeRect.fLeft, freeRect.fTop, width, height);
- result.surface = mSurface;
- auto eraseIt = mRects.emplace(mRects.end(), result.rect, freeRect, nullptr);
- CacheEntry* entry = &(*eraseIt);
- entry->eraseIt = eraseIt;
- result.key = reinterpret_cast<AtlasKey>(entry);
- mPixelUsedByVDs += area;
- mFreeRects.erase(freeRectIt);
- mConsecutiveFailures = 0;
- return result;
- }
- freeRectIt++;
- }
-
- if (notTooBig && mConsecutiveFailures <= MAX_CONSECUTIVE_FAILURES) {
- mConsecutiveFailures++;
- }
- }
-
- // Allocate a surface for a rectangle that is too big or if atlas is full.
- if (nullptr != context) {
- result.rect = SkRect::MakeWH(width, height);
- result.surface = createSurface(width, height, context);
- auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, result.surface);
- CacheEntry* entry = &(*eraseIt);
- entry->eraseIt = eraseIt;
- result.key = reinterpret_cast<AtlasKey>(entry);
- }
-
- return result;
-}
-
-AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) {
- AtlasEntry result;
- if (INVALID_ATLAS_KEY != atlasKey) {
- CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey);
- result.rect = entry->VDrect;
- result.surface = entry->surface;
- if (!result.surface) {
- result.surface = mSurface;
- }
- result.key = atlasKey;
- }
- return result;
-}
-
-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
- // is full.
- SkRect& removedRect = entry->rect;
- size_t rectArea = removedRect.width() * removedRect.height();
- mFreeRects.emplace(rectArea, removedRect);
- SkRect& removedVDRect = entry->VDrect;
- size_t VDRectArea = removedVDRect.width() * removedVDRect.height();
- mPixelUsedByVDs -= VDRectArea;
- mConsecutiveFailures = 0;
- }
- auto eraseIt = entry->eraseIt;
- mRects.erase(eraseIt);
- }
-}
-
-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) {
- SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
- // This must have a top-left origin so that calls to surface->canvas->writePixels
- // performs a basic texture upload instead of a more complex drawing operation
- return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin,
- nullptr);
-}
-
-void VectorDrawableAtlas::setStorageMode(StorageMode mode) {
- mStorageMode = mode;
- if (StorageMode::disallowSharedSurface == mStorageMode && mSurface) {
- mSurface.reset();
- mRectanizer.reset();
- mFreeRects.clear();
- }
-}
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */