summaryrefslogtreecommitdiff
path: root/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/pipeline/skia/VectorDrawableAtlas.h')
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.h198
1 files changed, 198 insertions, 0 deletions
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
new file mode 100644
index 000000000000..496c55742748
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <SkSurface.h>
+#include <utils/FatVector.h>
+#include <utils/RefBase.h>
+#include <list>
+
+class GrRectanizer;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+typedef uintptr_t AtlasKey;
+
+#define INVALID_ATLAS_KEY 0
+
+struct AtlasEntry {
+ sk_sp<SkSurface> surface;
+ SkRect rect;
+ AtlasKey key = INVALID_ATLAS_KEY;
+};
+
+/**
+ * VectorDrawableAtlas provides offscreen buffers used to draw VD and AnimatedVD.
+ * VectorDrawableAtlas can allocate a standalone surface or provide a subrect from a shared surface.
+ * VectorDrawableAtlas is owned by the CacheManager and weak pointers are kept by each
+ * VectorDrawable that is using it. VectorDrawableAtlas and its surface can be deleted at any time,
+ * except during a renderFrame call. VectorDrawable does not contain a pointer to atlas SkSurface
+ * nor any coordinates into the atlas, but instead holds a rectangle "id", which is resolved only
+ * when drawing. This design makes VectorDrawableAtlas free to move the data internally.
+ * At draw time a VectorDrawable may find, that its atlas has been deleted, which will make it
+ * draw in a standalone cache surface not part of an atlas. In this case VD won't use
+ * VectorDrawableAtlas until the next frame.
+ * VectorDrawableAtlas tries to fit VDs in the atlas SkSurface. If there is not enough space in
+ * the atlas, VectorDrawableAtlas creates a standalone surface for each VD.
+ * When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping
+ * track of free spaces and allow to reuse the surface for another VD.
+ */
+ //TODO: Check if not using atlas for AnimatedVD is more efficient.
+ //TODO: For low memory situations, when there are no paint effects in VD, we may render without an
+ //TODO: offscreen surface.
+class VectorDrawableAtlas : public virtual RefBase {
+public:
+ enum class StorageMode {
+ allowSharedSurface,
+ disallowSharedSurface
+ };
+
+ VectorDrawableAtlas(size_t surfaceArea,
+ StorageMode storageMode = StorageMode::allowSharedSurface);
+
+ /**
+ * "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
+ * atlas at a later time.
+ */
+ void prepareForDraw(GrContext* context);
+
+ /**
+ * Repack the atlas if needed, by moving used rectangles into a new atlas surface.
+ * The goal of repacking is to fix a fragmented atlas.
+ */
+ void repackIfNeeded(GrContext* context);
+
+ /**
+ * Returns true if atlas is fragmented and repack is needed.
+ */
+ bool isFragmented();
+
+ /**
+ * "requestNewEntry" is called by VectorDrawable to allocate a new rectangle area from the atlas
+ * or create a standalone surface if atlas is full.
+ * On success it returns a non-negative unique id, which can be used later with "getEntry" and
+ * "releaseEntry".
+ */
+ AtlasEntry requestNewEntry(int width, int height, GrContext* context);
+
+ /**
+ * "getEntry" extracts coordinates and surface of a previously created rectangle.
+ * "atlasKey" is an unique id created by "requestNewEntry". Passing a non-existing "atlasKey" is
+ * causing an undefined behaviour.
+ * On success it returns a rectangle Id -> may be same or different from "atlasKey" if
+ * implementation decides to move the record internally.
+ */
+ AtlasEntry getEntry(AtlasKey atlasKey);
+
+ /**
+ * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey"
+ * is causing an undefined behaviour.
+ */
+ void releaseEntry(AtlasKey atlasKey);
+
+ void setStorageMode(StorageMode mode);
+
+private:
+ struct CacheEntry {
+ CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
+ const sk_sp<SkSurface>& newSurface)
+ : VDrect(newVDrect)
+ , rect(newRect)
+ , surface(newSurface) { }
+
+ /**
+ * size and position of VectorDrawable into the atlas or in "this.surface"
+ */
+ SkRect VDrect;
+
+ /**
+ * rect allocated in atlas surface or "this.surface". It may be bigger than "VDrect"
+ */
+ SkRect rect;
+
+ /**
+ * this surface is used if atlas is full or VD is too big
+ */
+ sk_sp<SkSurface> surface;
+
+ /**
+ * iterator is used to delete self with a constant complexity (without traversing the list)
+ */
+ std::list<CacheEntry>::iterator eraseIt;
+ };
+
+ /**
+ * atlas surface shared by all VDs
+ */
+ sk_sp<SkSurface> mSurface;
+
+ std::unique_ptr<GrRectanizer> mRectanizer;
+ const int mWidth;
+ const int mHeight;
+
+ /**
+ * "mRects" keeps records only for rectangles used by VDs. List has nice properties: constant
+ * complexity to insert and erase and references are not invalidated by insert/erase.
+ */
+ std::list<CacheEntry> mRects;
+
+ /**
+ * Rectangles freed by "releaseEntry" are removed from "mRects" and added to "mFreeRects".
+ * "mFreeRects" is using for an index the rectangle area. There could be more than one free
+ * rectangle with the same area, which is the reason to use "multimap" instead of "map".
+ */
+ std::multimap<size_t, SkRect> mFreeRects;
+
+ /**
+ * area in atlas used by VectorDrawables (area in standalone surface not counted)
+ */
+ int mPixelUsedByVDs = 0;
+
+ /**
+ * area allocated in mRectanizer
+ */
+ int mPixelAllocated = 0;
+
+ /**
+ * Consecutive times we had to allocate standalone surfaces, because atlas was full.
+ */
+ int mConsecutiveFailures = 0;
+
+ /**
+ * mStorageMode allows using a shared surface to store small vector drawables.
+ * Using a shared surface can boost the performance by allowing GL ops to be batched, but may
+ * consume more memory.
+ */
+ StorageMode mStorageMode;
+
+ sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
+
+ inline bool fitInAtlas(int width, int height) {
+ return 2*width < mWidth && 2*height < mHeight;
+ }
+
+ void repack(GrContext* context);
+
+ static bool compareCacheEntry(const CacheEntry& first, const CacheEntry& second);
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */