1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_HWUI_ASSET_ATLAS_H
18 #define ANDROID_HWUI_ASSET_ATLAS_H
19 
20 #include "Texture.h"
21 #include "UvMapper.h"
22 
23 #include <cutils/compiler.h>
24 #include <GLES2/gl2.h>
25 #include <ui/GraphicBuffer.h>
26 #include <SkBitmap.h>
27 
28 #include <memory>
29 #include <unordered_map>
30 
31 namespace android {
32 namespace uirenderer {
33 
34 class Caches;
35 class Image;
36 
37 /**
38  * An asset atlas holds a collection of framework bitmaps in a single OpenGL
39  * texture. Each bitmap is associated with a location, defined in pixels,
40  * inside the atlas. The atlas is generated by the framework and bound as
41  * an external texture using the EGLImageKHR extension.
42  */
43 class AssetAtlas {
44 public:
45     /**
46      * Entry representing the texture and uvMapper of a PixelRef in the
47      * atlas
48      */
49     class Entry {
50     public:
51         /*
52          * A "virtual texture" object that represents the texture
53          * this entry belongs to. This texture should never be
54          * modified.
55          */
56         Texture* texture;
57 
58         /**
59          * Maps texture coordinates in the [0..1] range into the
60          * correct range to sample this entry from the atlas.
61          */
62         const UvMapper uvMapper;
63 
64         /**
65          * Unique identifier used to merge bitmaps and 9-patches stored
66          * in the atlas.
67          */
getMergeId()68         const void* getMergeId() const {
69             return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey;
70         }
71 
~Entry()72         ~Entry() {
73             delete texture;
74         }
75 
76     private:
77         /**
78          * The pixel ref that generated this atlas entry.
79          */
80         SkPixelRef* pixelRef;
81 
82         /**
83          * Atlas this entry belongs to.
84          */
85         const AssetAtlas& atlas;
86 
Entry(SkPixelRef * pixelRef,Texture * texture,const UvMapper & mapper,const AssetAtlas & atlas)87         Entry(SkPixelRef* pixelRef, Texture* texture, const UvMapper& mapper,
88                     const AssetAtlas& atlas)
89                 : texture(texture)
90                 , uvMapper(mapper)
91                 , pixelRef(pixelRef)
92                 , atlas(atlas) {
93         }
94 
95         friend class AssetAtlas;
96     };
97 
AssetAtlas()98     AssetAtlas(): mTexture(nullptr), mImage(nullptr),
99             mBlendKey(true), mOpaqueKey(false) { }
~AssetAtlas()100     ~AssetAtlas() { terminate(); }
101 
102     /**
103      * Initializes the atlas with the specified buffer and
104      * map. The buffer is a gralloc'd texture that will be
105      * used as an EGLImage. The map is a list of SkBitmap*
106      * and their (x, y) positions
107      *
108      * This method returns immediately if the atlas is already
109      * initialized. To re-initialize the atlas, you must
110      * first call terminate().
111      */
112     ANDROID_API void init(sp<GraphicBuffer> buffer, int64_t* map, int count);
113 
114     /**
115      * Destroys the atlas texture. This object can be
116      * re-initialized after calling this method.
117      *
118      * After calling this method, the width, height
119      * and texture are set to 0.
120      */
121     void terminate();
122 
123     /**
124      * Returns the width of this atlas in pixels.
125      * Can return 0 if the atlas is not initialized.
126      */
getWidth()127     uint32_t getWidth() const {
128         return mTexture ? mTexture->width() : 0;
129     }
130 
131     /**
132      * Returns the height of this atlas in pixels.
133      * Can return 0 if the atlas is not initialized.
134      */
getHeight()135     uint32_t getHeight() const {
136         return mTexture ? mTexture->height() : 0;
137     }
138 
139     /**
140      * Returns the OpenGL name of the texture backing this atlas.
141      * Can return 0 if the atlas is not initialized.
142      */
getTexture()143     GLuint getTexture() const {
144         return mTexture ? mTexture->id() : 0;
145     }
146 
147     /**
148      * Returns the entry in the atlas associated with the specified
149      * pixelRef. If the pixelRef is not in the atlas, return NULL.
150      */
151     Entry* getEntry(const SkPixelRef* pixelRef) const;
152 
153     /**
154      * Returns the texture for the atlas entry associated with the
155      * specified pixelRef. If the pixelRef is not in the atlas, return NULL.
156      */
157     Texture* getEntryTexture(const SkPixelRef* pixelRef) const;
158 
159 private:
160     void createEntries(Caches& caches, int64_t* map, int count);
161 
162     Texture* mTexture;
163     Image* mImage;
164 
165     const bool mBlendKey;
166     const bool mOpaqueKey;
167 
168     std::unordered_map<const SkPixelRef*, std::unique_ptr<Entry>> mEntries;
169 }; // class AssetAtlas
170 
171 }; // namespace uirenderer
172 }; // namespace android
173 
174 #endif // ANDROID_HWUI_ASSET_ATLAS_H
175