1 /*
2  * Copyright (C) 2015 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 #include "renderstate/MeshState.h"
17 
18 #include "Program.h"
19 
20 #include "ShadowTessellator.h"
21 
22 namespace android {
23 namespace uirenderer {
24 
MeshState()25 MeshState::MeshState()
26         : mCurrentIndicesBuffer(0)
27         , mCurrentPixelBuffer(0)
28         , mCurrentPositionPointer(this)
29         , mCurrentPositionStride(0)
30         , mCurrentTexCoordsPointer(this)
31         , mCurrentTexCoordsStride(0)
32         , mTexCoordsArrayEnabled(false)
33         , mQuadListIndices(0) {
34     glGenBuffers(1, &mUnitQuadBuffer);
35     glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
36     glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
37     mCurrentBuffer = mUnitQuadBuffer;
38 
39     uint16_t regionIndices[kMaxNumberOfQuads * 6];
40     for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
41         uint16_t quad = i * 4;
42         int index = i * 6;
43         regionIndices[index    ] = quad;       // top-left
44         regionIndices[index + 1] = quad + 1;   // top-right
45         regionIndices[index + 2] = quad + 2;   // bottom-left
46         regionIndices[index + 3] = quad + 2;   // bottom-left
47         regionIndices[index + 4] = quad + 1;   // top-right
48         regionIndices[index + 5] = quad + 3;   // bottom-right
49     }
50     glGenBuffers(1, &mQuadListIndices);
51     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
52     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW);
53     mCurrentIndicesBuffer = mQuadListIndices;
54 
55     // position attribute always enabled
56     glEnableVertexAttribArray(Program::kBindingPosition);
57 }
58 
~MeshState()59 MeshState::~MeshState() {
60     glDeleteBuffers(1, &mUnitQuadBuffer);
61     mCurrentBuffer = 0;
62 
63     glDeleteBuffers(1, &mQuadListIndices);
64     mQuadListIndices = 0;
65 }
66 
dump()67 void MeshState::dump() {
68     ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
69     ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
70     ALOGD("MeshState vertices: vertex data %p, stride %d",
71             mCurrentPositionPointer, mCurrentPositionStride);
72     ALOGD("MeshState texCoord: data %p, stride %d",
73             mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////
77 // Buffer Objects
78 ///////////////////////////////////////////////////////////////////////////////
79 
bindMeshBuffer(GLuint buffer)80 void MeshState::bindMeshBuffer(GLuint buffer) {
81     if (mCurrentBuffer != buffer) {
82         glBindBuffer(GL_ARRAY_BUFFER, buffer);
83         mCurrentBuffer = buffer;
84 
85         // buffer has changed, so invalidate cached vertex pos/texcoord pointers
86         resetVertexPointers();
87     }
88 }
89 
unbindMeshBuffer()90 void MeshState::unbindMeshBuffer() {
91     return bindMeshBuffer(0);
92 }
93 
genOrUpdateMeshBuffer(GLuint * buffer,GLsizeiptr size,const void * data,GLenum usage)94 void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
95         const void* data, GLenum usage) {
96     if (!*buffer) {
97         glGenBuffers(1, buffer);
98     }
99     bindMeshBuffer(*buffer);
100     glBufferData(GL_ARRAY_BUFFER, size, data, usage);
101 }
102 
deleteMeshBuffer(GLuint buffer)103 void MeshState::deleteMeshBuffer(GLuint buffer) {
104     if (buffer == mCurrentBuffer) {
105         // GL defines that deleting the currently bound VBO rebinds to 0 (no VBO).
106         // Reflect this in our cached value.
107         mCurrentBuffer = 0;
108     }
109     glDeleteBuffers(1, &buffer);
110 }
111 
112 ///////////////////////////////////////////////////////////////////////////////
113 // Vertices
114 ///////////////////////////////////////////////////////////////////////////////
115 
bindPositionVertexPointer(const GLvoid * vertices,GLsizei stride)116 void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
117     // update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
118     if (mCurrentBuffer == 0
119             || vertices != mCurrentPositionPointer
120             || stride != mCurrentPositionStride) {
121         glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
122         mCurrentPositionPointer = vertices;
123         mCurrentPositionStride = stride;
124     }
125 }
126 
bindTexCoordsVertexPointer(const GLvoid * vertices,GLsizei stride)127 void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
128     // update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
129     if (mCurrentBuffer == 0
130             || vertices != mCurrentTexCoordsPointer
131             || stride != mCurrentTexCoordsStride) {
132         glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
133         mCurrentTexCoordsPointer = vertices;
134         mCurrentTexCoordsStride = stride;
135     }
136 }
137 
resetVertexPointers()138 void MeshState::resetVertexPointers() {
139     mCurrentPositionPointer = this;
140     mCurrentTexCoordsPointer = this;
141 }
142 
enableTexCoordsVertexArray()143 void MeshState::enableTexCoordsVertexArray() {
144     if (!mTexCoordsArrayEnabled) {
145         glEnableVertexAttribArray(Program::kBindingTexCoords);
146         mCurrentTexCoordsPointer = this;
147         mTexCoordsArrayEnabled = true;
148     }
149 }
150 
disableTexCoordsVertexArray()151 void MeshState::disableTexCoordsVertexArray() {
152     if (mTexCoordsArrayEnabled) {
153         glDisableVertexAttribArray(Program::kBindingTexCoords);
154         mTexCoordsArrayEnabled = false;
155     }
156 }
157 
158 ///////////////////////////////////////////////////////////////////////////////
159 // Indices
160 ///////////////////////////////////////////////////////////////////////////////
161 
bindIndicesBuffer(const GLuint buffer)162 void MeshState::bindIndicesBuffer(const GLuint buffer) {
163     if (mCurrentIndicesBuffer != buffer) {
164         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
165         mCurrentIndicesBuffer = buffer;
166     }
167 }
168 
unbindIndicesBuffer()169 void MeshState::unbindIndicesBuffer() {
170     if (mCurrentIndicesBuffer) {
171         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
172         mCurrentIndicesBuffer = 0;
173     }
174 }
175 
176 } /* namespace uirenderer */
177 } /* namespace android */
178 
179