/* * 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> #define STR(s) #s #define STRV(s) STR(s) #define POS_ATTRIB 0 #define COLOR_ATTRIB 1 #define SCALEROT_ATTRIB 2 #define OFFSET_ATTRIB 3 static const char VERTEX_SHADER[] = "#version 300 es\n" "layout(location = " STRV(POS_ATTRIB) ") in vec2 pos;\n" "layout(location=" STRV(COLOR_ATTRIB) ") in vec4 color;\n" "layout(location=" STRV(SCALEROT_ATTRIB) ") in vec4 scaleRot;\n" "layout(location=" STRV(OFFSET_ATTRIB) ") in vec2 offset;\n" "out vec4 vColor;\n" "void main() {\n" " mat2 sr = mat2(scaleRot.xy, scaleRot.zw);\n" " gl_Position = vec4(sr*pos + offset, 0.0, 1.0);\n" " vColor = color;\n" "}\n"; static const char FRAGMENT_SHADER[] = "#version 300 es\n" "precision mediump float;\n" "in vec4 vColor;\n" "out vec4 outColor;\n" "void main() {\n" " outColor = vColor;\n" "}\n"; class RendererES3: public Renderer { public: RendererES3(); virtual ~RendererES3(); bool init(); private: enum {VB_INSTANCE, VB_SCALEROT, VB_OFFSET, VB_COUNT}; 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[VB_COUNT]; GLuint mVBState; }; Renderer* createES3Renderer() { RendererES3* renderer = new RendererES3; if (!renderer->init()) { delete renderer; return NULL; } return renderer; } RendererES3::RendererES3() : mEglContext(eglGetCurrentContext()), mProgram(0), mVBState(0) { for (int i = 0; i < VB_COUNT; i++) mVB[i] = 0; } bool RendererES3::init() { mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER); if (!mProgram) return false; glGenBuffers(VB_COUNT, mVB); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_INSTANCE]); glBufferData(GL_ARRAY_BUFFER, sizeof(QUAD), &QUAD[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]); glBufferData(GL_ARRAY_BUFFER, MAX_INSTANCES * 4*sizeof(float), NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]); glBufferData(GL_ARRAY_BUFFER, MAX_INSTANCES * 2*sizeof(float), NULL, GL_STATIC_DRAW); glGenVertexArrays(1, &mVBState); glBindVertexArray(mVBState); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_INSTANCE]); glVertexAttribPointer(POS_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, pos)); glVertexAttribPointer(COLOR_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (const GLvoid*)offsetof(Vertex, rgba)); glEnableVertexAttribArray(POS_ATTRIB); glEnableVertexAttribArray(COLOR_ATTRIB); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]); glVertexAttribPointer(SCALEROT_ATTRIB, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0); glEnableVertexAttribArray(SCALEROT_ATTRIB); glVertexAttribDivisor(SCALEROT_ATTRIB, 1); glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]); glVertexAttribPointer(OFFSET_ATTRIB, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), 0); glEnableVertexAttribArray(OFFSET_ATTRIB); glVertexAttribDivisor(OFFSET_ATTRIB, 1); ALOGV("Using OpenGL ES 3.0 renderer"); return true; } RendererES3::~RendererES3() { /* 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; glDeleteVertexArrays(1, &mVBState); glDeleteBuffers(VB_COUNT, mVB); glDeleteProgram(mProgram); } float* RendererES3::mapOffsetBuf() { glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_OFFSET]); return (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, MAX_INSTANCES * 2*sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); } void RendererES3::unmapOffsetBuf() { glUnmapBuffer(GL_ARRAY_BUFFER); } float* RendererES3::mapTransformBuf() { glBindBuffer(GL_ARRAY_BUFFER, mVB[VB_SCALEROT]); return (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, MAX_INSTANCES * 4*sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); } void RendererES3::unmapTransformBuf() { glUnmapBuffer(GL_ARRAY_BUFFER); } void RendererES3::draw(unsigned int numInstances) { glUseProgram(mProgram); glBindVertexArray(mVBState); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, numInstances); }