1 /*
2  * Copyright (C) 2012 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_VERTEX_BUFFER_H
18 #define ANDROID_HWUI_VERTEX_BUFFER_H
19 
20 #include "utils/MathUtils.h"
21 
22 namespace android {
23 namespace uirenderer {
24 
25 class VertexBuffer {
26 public:
27     enum MeshFeatureFlags {
28         kNone = 0,
29         kAlpha = 1 << 0,
30         kIndices = 1 << 1,
31     };
32 
VertexBuffer()33     VertexBuffer()
34             : mBuffer(nullptr)
35             , mIndices(nullptr)
36             , mVertexCount(0)
37             , mIndexCount(0)
38             , mAllocatedVertexCount(0)
39             , mAllocatedIndexCount(0)
40             , mByteCount(0)
41             , mMeshFeatureFlags(kNone)
42             , mReallocBuffer(nullptr)
43             , mCleanupMethod(nullptr)
44             , mCleanupIndexMethod(nullptr)
45     {}
46 
~VertexBuffer()47     ~VertexBuffer() {
48         if (mCleanupMethod) mCleanupMethod(mBuffer);
49         if (mCleanupIndexMethod) mCleanupIndexMethod(mIndices);
50     }
51 
52     /**
53        This should be the only method used by the Tessellator. Subsequent calls to
54        alloc will allocate space within the first allocation (useful if you want to
55        eventually allocate multiple regions within a single VertexBuffer, such as
56        with PathTessellator::tessellateLines())
57      */
58     template <class TYPE>
alloc(int vertexCount)59     TYPE* alloc(int vertexCount) {
60         if (mVertexCount) {
61             TYPE* reallocBuffer = (TYPE*)mReallocBuffer;
62             // already have allocated the buffer, re-allocate space within
63             if (mReallocBuffer != mBuffer) {
64                 // not first re-allocation, leave space for degenerate triangles to separate strips
65                 reallocBuffer += 2;
66             }
67             mReallocBuffer = reallocBuffer + vertexCount;
68             return reallocBuffer;
69         }
70         mAllocatedVertexCount = vertexCount;
71         mVertexCount = vertexCount;
72         mByteCount = mVertexCount * sizeof(TYPE);
73         mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
74 
75         mCleanupMethod = &(cleanup<TYPE>);
76 
77         return (TYPE*)mBuffer;
78     }
79 
80     template <class TYPE>
allocIndices(int indexCount)81     TYPE* allocIndices(int indexCount) {
82         mAllocatedIndexCount = indexCount;
83         mIndexCount = indexCount;
84         mIndices = (void*)new TYPE[indexCount];
85 
86         mCleanupIndexMethod = &(cleanup<TYPE>);
87 
88         return (TYPE*)mIndices;
89     }
90 
91     template <class TYPE>
copyInto(const VertexBuffer & srcBuffer,float xOffset,float yOffset)92     void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
93         int verticesToCopy = srcBuffer.getVertexCount();
94 
95         TYPE* dst = alloc<TYPE>(verticesToCopy);
96         TYPE* src = (TYPE*)srcBuffer.getBuffer();
97 
98         for (int i = 0; i < verticesToCopy; i++) {
99             TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset);
100         }
101     }
102 
103     /**
104      * Brute force bounds computation, used only if the producer of this
105      * vertex buffer can't determine bounds more simply/efficiently
106      */
107     template <class TYPE>
108     void computeBounds(int vertexCount = 0) {
109         if (!mVertexCount) {
110             mBounds.setEmpty();
111             return;
112         }
113 
114         // default: compute over every vertex
115         if (vertexCount == 0) vertexCount = mVertexCount;
116 
117         TYPE* current = (TYPE*)mBuffer;
118         TYPE* end = current + vertexCount;
119         mBounds.set(current->x, current->y, current->x, current->y);
120         for (; current < end; current++) {
121             mBounds.expandToCoverVertex(current->x, current->y);
122         }
123     }
124 
getBuffer()125     const void* getBuffer() const { return mBuffer; }
getIndices()126     const void* getIndices() const { return mIndices; }
getBounds()127     const Rect& getBounds() const { return mBounds; }
getVertexCount()128     unsigned int getVertexCount() const { return mVertexCount; }
getSize()129     unsigned int getSize() const { return mByteCount; }
getIndexCount()130     unsigned int getIndexCount() const { return mIndexCount; }
updateIndexCount(unsigned int newCount)131     void updateIndexCount(unsigned int newCount)  {
132         mIndexCount = MathUtils::min(newCount, mAllocatedIndexCount);
133     }
updateVertexCount(unsigned int newCount)134     void updateVertexCount(unsigned int newCount)  {
135         mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
136     }
getMeshFeatureFlags()137     MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
setMeshFeatureFlags(int flags)138     void setMeshFeatureFlags(int flags) {
139         mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
140     }
141 
setBounds(Rect bounds)142     void setBounds(Rect bounds) { mBounds = bounds; }
143 
144     template <class TYPE>
createDegenerateSeparators(int allocSize)145     void createDegenerateSeparators(int allocSize) {
146         TYPE* end = (TYPE*)mBuffer + mVertexCount;
147         for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) {
148             memcpy(degen, degen - 1, sizeof(TYPE));
149             memcpy(degen + 1, degen + 2, sizeof(TYPE));
150         }
151     }
152 
153 private:
154     template <class TYPE>
cleanup(void * buffer)155     static void cleanup(void* buffer) {
156         delete[] (TYPE*)buffer;
157     }
158 
159     Rect mBounds;
160 
161     void* mBuffer;
162     void* mIndices;
163 
164     unsigned int mVertexCount;
165     unsigned int mIndexCount;
166     unsigned int mAllocatedVertexCount;
167     unsigned int mAllocatedIndexCount;
168     unsigned int mByteCount;
169 
170     MeshFeatureFlags mMeshFeatureFlags;
171 
172     void* mReallocBuffer; // used for multi-allocation
173 
174     void (*mCleanupMethod)(void*);
175     void (*mCleanupIndexMethod)(void*);
176 };
177 
178 }; // namespace uirenderer
179 }; // namespace android
180 
181 #endif // ANDROID_HWUI_VERTEX_BUFFER_H
182