blob: 835ed8a51be69148db3da3f7c31e2eddd0dd2b84 [file] [log] [blame]
Mathias Agopian3f844832013-08-07 21:24:32 -07001/*
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 <GLES2/gl2.h>
18#include <GLES2/gl2ext.h>
19
20#include <utils/String8.h>
21
22#include "ProgramCache.h"
23#include "Program.h"
24#include "Description.h"
25
26namespace android {
27// -----------------------------------------------------------------------------------------------
28
29
30/*
31 * A simple formatter class to automatically add the endl and
32 * manage the indentation.
33 */
34
35class Formatter;
36static Formatter& indent(Formatter& f);
37static Formatter& dedent(Formatter& f);
38
39class Formatter {
40 String8 mString;
41 int mIndent;
42 typedef Formatter& (*FormaterManipFunc)(Formatter&);
43 friend Formatter& indent(Formatter& f);
44 friend Formatter& dedent(Formatter& f);
45public:
46 String8 getString() const {
47 return mString;
48 }
49
50 friend Formatter& operator << (Formatter& out, const char* in) {
51 for (int i=0 ; i<out.mIndent ; i++) {
52 out.mString.append(" ");
53 }
54 out.mString.append(in);
55 out.mString.append("\n");
56 return out;
57 }
58 friend inline Formatter& operator << (Formatter& out, const String8& in) {
59 return operator << (out, in.string());
60 }
61 friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
62 return (*func)(to);
63 }
64};
65Formatter& indent(Formatter& f) {
66 f.mIndent++;
67 return f;
68}
69Formatter& dedent(Formatter& f) {
70 f.mIndent--;
71 return f;
72}
73
74// -----------------------------------------------------------------------------------------------
75
76ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
77
78
79ProgramCache::ProgramCache() {
80}
81
82ProgramCache::~ProgramCache() {
83}
84
85ProgramCache::Key ProgramCache::computeKey(const Description& description) {
86 Key needs;
87 needs.set(Key::TEXTURE_MASK,
88 (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT :
89 (description.mTextureTarget == GL_TEXTURE_2D) ? Key::TEXTURE_2D :
90 Key::TEXTURE_OFF)
91 .set(Key::PLANE_ALPHA_MASK,
92 (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
93 .set(Key::BLEND_MASK,
94 description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
95 .set(Key::OPACITY_MASK,
96 description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
97 return needs;
98}
99
100String8 ProgramCache::generateVertexShader(const Key& needs) {
101 Formatter vs;
102 if (needs.isTexturing()) {
103 vs << "attribute vec4 texCoords;"
104 << "varying vec2 outTexCoords;";
105 }
106 vs << "attribute vec4 position;"
107 << "uniform mat4 projection;"
108 << "uniform mat4 texture;"
109 << "void main(void) {" << indent
110 << "gl_Position = projection * position;";
111 if (needs.isTexturing()) {
112 vs << "outTexCoords = (texture * texCoords).st;";
113 }
114 vs << dedent << "}";
115 return vs.getString();
116}
117
118String8 ProgramCache::generateFragmentShader(const Key& needs) {
119 Formatter fs;
120 if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
121 fs << "#extension GL_OES_EGL_image_external : require";
122 }
123 if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
124 fs << "uniform samplerExternalOES sampler;"
125 << "varying vec2 outTexCoords;";
126 } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
127 fs << "uniform sampler2D sampler;"
128 << "varying vec2 outTexCoords;";
129 } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
130 fs << "uniform vec4 color;";
131 }
132 if (needs.hasPlaneAlpha()) {
133 fs << "uniform float alphaPlane;";
134 }
135 fs << "void main(void) {" << indent;
136 if (needs.isTexturing()) {
137 fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
138 } else {
139 fs << "gl_FragColor = color;";
140 }
141 if (needs.hasPlaneAlpha()) {
142 // modulate the alpha value with planeAlpha
143 if (needs.isPremultiplied()) {
144 // ... and the color too if we're premultiplied
145 if (needs.isOpaque()) {
146 // ... we're opaque, only premultiply the color component
147 fs << "gl_FragColor.rgb *= alphaPlane;"
148 << "gl_FragColor.a = alphaPlane;";
149 } else {
150 fs << "gl_FragColor *= alphaPlane;";
151 }
152 } else {
153 // not premultiplied
154 if (needs.isOpaque()) {
155 fs << "gl_FragColor.a = alphaPlane;";
156 } else {
157 fs << "gl_FragColor.a *= alphaPlane;";
158 }
159 }
160 } else {
161 if (needs.isOpaque()) {
162 fs << "gl_FragColor.a = 1.0;";
163 }
164 }
165 fs << dedent << "}";
166 return fs.getString();
167}
168
169Program* ProgramCache::generateProgram(const Key& needs) {
170 // vertex shader
171 String8 vs = generateVertexShader(needs);
172
173 // fragment shader
174 String8 fs = generateFragmentShader(needs);
175
176 Program* program = new Program(needs, vs.string(), fs.string());
177 return program;
178}
179
180void ProgramCache::useProgram(const Description& description) {
181
182 // generate the key for the shader based on the description
183 Key needs(computeKey(description));
184
185 // look-up the program in the cache
186 Program* program = mCache.valueFor(needs);
187 if (program == NULL) {
188 // we didn't find our program, so generate one...
189 nsecs_t time = -systemTime();
190 program = generateProgram(needs);
191 mCache.add(needs, program);
192 time += systemTime();
193
194 //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
195 // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
196 }
197
198 // here we have a suitable program for this description
199 if (program->isValid()) {
200 program->use();
201 program->setUniforms(description);
202 }
203}
204
205
206} /* namespace android */