OSDN Git Service

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