/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "gles3jni.h" #include <EGL/egl.h> static const char VERTEX_SHADER[] = "#version 100\n" "uniform mat2 scaleRot;\n" "uniform vec2 offset;\n" "attribute vec2 pos;\n" "attribute vec4 color;\n" "varying vec4 vColor;\n" "void main() {\n" " gl_Position = vec4(scaleRot*pos + offset, 0.0, 1.0);\n" " vColor = color;\n" "}\n"; static const char FRAGMENT_SHADER[] = "#version 100\n" "precision mediump float;\n" "varying vec4 vColor;\n" "void main() {\n" " gl_FragColor = vColor;\n" "}\n"; class RendererES2: public Renderer { public: RendererES2(); virtual ~RendererES2(); bool init(); private: virtual float* mapOffsetBuf(); virtual void unmapOffsetBuf(); virtual float* mapTransformBuf(); virtual void unmapTransformBuf(); virtual void draw(unsigned int numInstances); const EGLContext mEglContext; GLuint mProgram; GLuint mVB; GLint mPosAttrib; GLint mColorAttrib; GLint mScaleRotUniform; GLint mOffsetUniform; float mOffsets[2*MAX_INSTANCES]; float mScaleRot[4*MAX_INSTANCES]; // array of 2x2 column-major matrices }; Renderer* createES2Renderer() { RendererES2* renderer = new RendererES2; if (!renderer->init()) { delete renderer; return NULL; } return renderer; } RendererES2::RendererES2() : mEglContext(eglGetCurrentContext()), mProgram(0), mVB(0), mPosAttrib(-1), mColorAttrib(-1), mScaleRotUniform(-1), mOffsetUniform(-1) {} bool RendererES2::init() { mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER); if (!mProgram) return false; mPosAttrib = glGetAttribLocation(mProgram, "pos"); mColorAttrib = glGetAttribLocation(mProgram, "color"); mScaleRotUniform = glGetUniformLocation(mProgram, "scaleRot"); mOffsetUniform = glGetUniformLocation(mProgram, "offset"); glGenBuffers(1, &mVB); glBindBuffer(GL_ARRAY_BUFFER, mVB); glBufferData(GL_ARRAY_BUFFER, sizeof(QUAD), &QUAD[0], GL_STATIC_DRAW); ALOGV("Using OpenGL ES 2.0 renderer"); return true; } RendererES2::~RendererES2() { /* The destructor may be called after the context has already been * destroyed, in which case our objects have already been destroyed. * * If the context exists, it must be current. This only happens when we're * cleaning up after a failed init(). */ if (eglGetCurrentContext() != mEglContext) return; glDeleteBuffers(1, &mVB); glDeleteProgram(mProgram); } float* RendererES2::mapOffsetBuf() { return mOffsets; } void RendererES2::unmapOffsetBuf() { } float* RendererES2::mapTransformBuf() { return mScaleRot; } void RendererES2::unmapTransformBuf() { } void RendererES2::draw(unsigned int numInstances) { glUseProgram(mProgram); glBindBuffer(GL_ARRAY_BUFFER, mVB); glVertexAttribPointer(mPosAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, pos)); glVertexAttribPointer(mColorAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, rgba)); glEnableVertexAttribArray(mPosAttrib); glEnableVertexAttribArray(mColorAttrib); for (unsigned int i = 0; i < numInstances; i++) { glUniformMatrix2fv(mScaleRotUniform, 1, GL_FALSE, mScaleRot + 4*i); glUniform2fv(mOffsetUniform, 1, mOffsets + 2*i); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } }