1/*
2 * Copyright 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#include "gles3jni.h"
18#include <EGL/egl.h>
19
20#define STR(s) #s
21#define STRV(s) STR(s)
22
23#define POS_ATTRIB 0
24#define COLOR_ATTRIB 1
25#define SCALEROT_ATTRIB 2
26#define OFFSET_ATTRIB 3
27
28static const char VERTEX_SHADER[] =
29    "#version 300 es\n"
30    "layout(location = " STRV(POS_ATTRIB) ") in vec2 pos;\n"
31    "layout(location=" STRV(COLOR_ATTRIB) ") in vec4 color;\n"
32    "layout(location=" STRV(SCALEROT_ATTRIB) ") in vec4 scaleRot;\n"
33    "layout(location=" STRV(OFFSET_ATTRIB) ") in vec2 offset;\n"
34    "out vec4 vColor;\n"
35    "void main() {\n"
36    "    mat2 sr = mat2(scaleRot.xy, scaleRot.zw);\n"
37    "    gl_Position = vec4(sr*pos + offset, 0.0, 1.0);\n"
38    "    vColor = color;\n"
39    "}\n";
40
41static const char FRAGMENT_SHADER[] =
42    "#version 300 es\n"
43    "precision mediump float;\n"
44    "in vec4 vColor;\n"
45    "out vec4 outColor;\n"
46    "void main() {\n"
47    "    outColor = vColor;\n"
48    "}\n";
49
50class RendererES3: public Renderer {
51public:
52    RendererES3();
53    virtual ~RendererES3();
54    bool init();
55
56private:
57    enum {VB_INSTANCE, VB_SCALEROT, VB_OFFSET, VB_COUNT};
58
59    virtual float* mapOffsetBuf();
60    virtual void unmapOffsetBuf();
61    virtual float* mapTransformBuf();
62    virtual void unmapTransformBuf();
63    virtual void draw(unsigned int numInstances);
64
65    const EGLContext mEglContext;
66    GLuint mProgram;
67    GLuint mVB[VB_COUNT];
68    GLuint mVBState;
69};
70
71Renderer* createES3Renderer() {
72    RendererES3* renderer = new RendererES3;
73    if (!renderer->init()) {
74        delete renderer;
75        return NULL;
76    }
77    return renderer;
78}
79
80RendererES3::RendererES3()
81:   mEglContext(eglGetCurrentContext()),
82    mProgram(0),
83    mVBState(0)
84{
85    for (int i = 0; i < VB_COUNT; i++)
86        mVB[i] = 0;
87}
88
89bool RendererES3::init() {
90    mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
91    if (!mProgram)
92        return false;
93
94    glGenBuffers(VB_COUNT, mVB);
95    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_INSTANCE]);
96    glBufferData(GL_ARRAY_BUFFER, sizeof(QUAD), &QUAD[0], GL_STATIC_DRAW);
97    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]);
98    glBufferData(GL_ARRAY_BUFFER, MAX_INSTANCES * 4*sizeof(float), NULL, GL_DYNAMIC_DRAW);
99    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]);
100    glBufferData(GL_ARRAY_BUFFER, MAX_INSTANCES * 2*sizeof(float), NULL, GL_STATIC_DRAW);
101
102    glGenVertexArrays(1, &mVBState);
103    glBindVertexArray(mVBState);
104
105    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_INSTANCE]);
106    glVertexAttribPointer(POS_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, pos));
107    glVertexAttribPointer(COLOR_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, rgba));
108    glEnableVertexAttribArray(POS_ATTRIB);
109    glEnableVertexAttribArray(COLOR_ATTRIB);
110
111    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]);
112    glVertexAttribPointer(SCALEROT_ATTRIB, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);
113    glEnableVertexAttribArray(SCALEROT_ATTRIB);
114    glVertexAttribDivisor(SCALEROT_ATTRIB, 1);
115
116    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]);
117    glVertexAttribPointer(OFFSET_ATTRIB, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), 0);
118    glEnableVertexAttribArray(OFFSET_ATTRIB);
119    glVertexAttribDivisor(OFFSET_ATTRIB, 1);
120
121    ALOGV("Using OpenGL ES 3.0 renderer");
122    return true;
123}
124
125RendererES3::~RendererES3() {
126    /* The destructor may be called after the context has already been
127     * destroyed, in which case our objects have already been destroyed.
128     *
129     * If the context exists, it must be current. This only happens when we're
130     * cleaning up after a failed init().
131     */
132    if (eglGetCurrentContext() != mEglContext)
133        return;
134    glDeleteVertexArrays(1, &mVBState);
135    glDeleteBuffers(VB_COUNT, mVB);
136    glDeleteProgram(mProgram);
137}
138
139float* RendererES3::mapOffsetBuf() {
140    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]);
141    return (float*)glMapBufferRange(GL_ARRAY_BUFFER,
142            0, MAX_INSTANCES * 2*sizeof(float),
143            GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
144}
145
146void RendererES3::unmapOffsetBuf() {
147    glUnmapBuffer(GL_ARRAY_BUFFER);
148}
149
150float* RendererES3::mapTransformBuf() {
151    glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]);
152    return (float*)glMapBufferRange(GL_ARRAY_BUFFER,
153            0, MAX_INSTANCES * 4*sizeof(float),
154            GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
155}
156
157void RendererES3::unmapTransformBuf() {
158    glUnmapBuffer(GL_ARRAY_BUFFER);
159}
160
161void RendererES3::draw(unsigned int numInstances) {
162    glUseProgram(mProgram);
163    glBindVertexArray(mVBState);
164    glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, numInstances);
165}
166