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