• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011-2012 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 <rs_hal.h>
18 #include <rsContext.h>
19 
20 #include "rsdShader.h"
21 #include "rsdShaderCache.h"
22 #include "rsdGL.h"
23 
24 #include <GLES/gl.h>
25 #include <GLES2/gl2.h>
26 
27 using namespace android;
28 using namespace android::renderscript;
29 
30 
RsdShaderCache()31 RsdShaderCache::RsdShaderCache() {
32     mEntries.setCapacity(16);
33     mVertexDirty = true;
34     mFragmentDirty = true;
35 }
36 
~RsdShaderCache()37 RsdShaderCache::~RsdShaderCache() {
38     cleanupAll();
39 }
40 
updateUniformArrayData(const Context * rsc,RsdShader * prog,uint32_t linkedID,UniformData * data,const char * logTag,UniformQueryData ** uniformList,uint32_t uniListSize)41 void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
42                                          UniformData *data, const char* logTag,
43                                          UniformQueryData **uniformList, uint32_t uniListSize) {
44 
45     for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
46         if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
47             //Iterate over the list of active GL uniforms and find highest array index
48             for (uint32_t ui = 0; ui < uniListSize; ui ++) {
49                 if (prog->getUniformName(ct) == uniformList[ui]->name) {
50                     data[ct].arraySize = (uint32_t)uniformList[ui]->arraySize;
51                     break;
52                 }
53             }
54         }
55 
56         if (rsc->props.mLogShaders) {
57              ALOGV("%s U, %s = %d, arraySize = %d\n", logTag,
58                   prog->getUniformName(ct).string(), data[ct].slot, data[ct].arraySize);
59         }
60     }
61 }
62 
populateUniformData(RsdShader * prog,uint32_t linkedID,UniformData * data)63 void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) {
64     for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
65        data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct));
66        data[ct].arraySize = prog->getUniformArraySize(ct);
67     }
68 }
69 
hasArrayUniforms(RsdShader * vtx,RsdShader * frag)70 bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) {
71     UniformData *data = mCurrent->vtxUniforms;
72     for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
73         if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
74             return true;
75         }
76     }
77     data = mCurrent->fragUniforms;
78     for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) {
79         if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
80             return true;
81         }
82     }
83     return false;
84 }
85 
setup(const Context * rsc)86 bool RsdShaderCache::setup(const Context *rsc) {
87     if (!mVertexDirty && !mFragmentDirty) {
88         return true;
89     }
90 
91     if (!link(rsc)) {
92         return false;
93     }
94 
95     if (mFragmentDirty) {
96         mFragment->setup(rsc, this);
97         mFragmentDirty = false;
98     }
99     if (mVertexDirty) {
100         mVertex->setup(rsc, this);
101         mVertexDirty = false;
102     }
103 
104     return true;
105 }
106 
link(const Context * rsc)107 bool RsdShaderCache::link(const Context *rsc) {
108 
109     RsdShader *vtx = mVertex;
110     RsdShader *frag = mFragment;
111 
112     uint32_t vID = vtx->getStateBasedShaderID(rsc);
113     uint32_t fID = frag->getStateBasedShaderID(rsc);
114 
115     // Don't try to cache if shaders failed to load
116     if (!vID || !fID) {
117         return false;
118     }
119     uint32_t entryCount = mEntries.size();
120     for (uint32_t ct = 0; ct < entryCount; ct ++) {
121         if ((mEntries[ct]->vtx == vID) && (mEntries[ct]->frag == fID)) {
122 
123             //ALOGV("SC using program %i", mEntries[ct]->program);
124             glUseProgram(mEntries[ct]->program);
125             mCurrent = mEntries[ct];
126             //ALOGV("RsdShaderCache hit, using %i", ct);
127             rsdGLCheckError(rsc, "RsdShaderCache::link (hit)");
128             return true;
129         }
130     }
131 
132     ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
133                                        vtx->getUniformCount(),
134                                        frag->getUniformCount());
135     mEntries.push(e);
136     mCurrent = e;
137     e->vtx = vID;
138     e->frag = fID;
139     e->program = glCreateProgram();
140     if (e->program) {
141         GLuint pgm = e->program;
142         glAttachShader(pgm, vID);
143         //ALOGE("e1 %x", glGetError());
144         glAttachShader(pgm, fID);
145 
146         glBindAttribLocation(pgm, 0, "ATTRIB_position");
147         glBindAttribLocation(pgm, 1, "ATTRIB_color");
148         glBindAttribLocation(pgm, 2, "ATTRIB_normal");
149         glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
150 
151         //ALOGE("e2 %x", glGetError());
152         glLinkProgram(pgm);
153         //ALOGE("e3 %x", glGetError());
154         GLint linkStatus = GL_FALSE;
155         glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus);
156         if (linkStatus != GL_TRUE) {
157             GLint bufLength = 0;
158             glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength);
159             if (bufLength) {
160                 char* buf = (char*) malloc(bufLength);
161                 if (buf) {
162                     glGetProgramInfoLog(pgm, bufLength, NULL, buf);
163                     rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
164                     free(buf);
165                 }
166             }
167             glDeleteProgram(pgm);
168             return false;
169         }
170 
171         for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) {
172             e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct));
173             e->vtxAttrs[ct].name = vtx->getAttribName(ct).string();
174             if (rsc->props.mLogShaders) {
175                 ALOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot);
176             }
177         }
178 
179         populateUniformData(vtx, pgm, e->vtxUniforms);
180         populateUniformData(frag, pgm, e->fragUniforms);
181 
182         // Only populate this list if we have arrays in our uniforms
183         UniformQueryData **uniformList = NULL;
184         GLint numUniforms = 0;
185         bool hasArrays = hasArrayUniforms(vtx, frag);
186         if (hasArrays) {
187             // Get the number of active uniforms and the length of the longest name
188             glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms);
189             GLint maxNameLength = 0;
190             glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
191             if (numUniforms > 0 && maxNameLength > 0) {
192                 uniformList = new UniformQueryData*[numUniforms];
193                 // Iterate over all the uniforms and build the list we
194                 // can later use to match our uniforms to
195                 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
196                     uniformList[ct] = new UniformQueryData(maxNameLength);
197                     glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength,
198                                        &uniformList[ct]->arraySize, &uniformList[ct]->type,
199                                        uniformList[ct]->name);
200                     //ALOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct,
201                     //     uniformList[ct]->arraySize, uniformList[ct]->name);
202                 }
203             }
204         }
205 
206         // We now know the highest index of all of the array uniforms
207         // and we need to update our cache to reflect that
208         // we may have declared [n], but only m < n elements are used
209         updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx",
210                                uniformList, (uint32_t)numUniforms);
211         updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag",
212                                uniformList, (uint32_t)numUniforms);
213 
214         // Clean up the uniform data from GL
215         if (uniformList != NULL) {
216             for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
217                 delete uniformList[ct];
218             }
219             delete[] uniformList;
220             uniformList = NULL;
221         }
222     }
223 
224     //ALOGV("SC made program %i", e->program);
225     glUseProgram(e->program);
226     rsdGLCheckError(rsc, "RsdShaderCache::link (miss)");
227 
228     return true;
229 }
230 
vtxAttribSlot(const String8 & attrName) const231 int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
232     for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
233         if (attrName == mCurrent->vtxAttrs[ct].name) {
234             return mCurrent->vtxAttrs[ct].slot;
235         }
236     }
237     return -1;
238 }
239 
cleanupVertex(RsdShader * s)240 void RsdShaderCache::cleanupVertex(RsdShader *s) {
241     int32_t numEntries = (int32_t)mEntries.size();
242     uint32_t numShaderIDs = s->getStateBasedIDCount();
243     for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
244         uint32_t id = s->getStateBasedID(sId);
245         for (int32_t ct = 0; ct < numEntries; ct ++) {
246             if (mEntries[ct]->vtx == id) {
247                 glDeleteProgram(mEntries[ct]->program);
248 
249                 delete mEntries[ct];
250                 mEntries.removeAt(ct);
251                 numEntries = (int32_t)mEntries.size();
252                 ct --;
253             }
254         }
255     }
256 }
257 
cleanupFragment(RsdShader * s)258 void RsdShaderCache::cleanupFragment(RsdShader *s) {
259     int32_t numEntries = (int32_t)mEntries.size();
260     uint32_t numShaderIDs = s->getStateBasedIDCount();
261     for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
262         uint32_t id = s->getStateBasedID(sId);
263         for (int32_t ct = 0; ct < numEntries; ct ++) {
264             if (mEntries[ct]->frag == id) {
265                 glDeleteProgram(mEntries[ct]->program);
266 
267                 delete mEntries[ct];
268                 mEntries.removeAt(ct);
269                 numEntries = (int32_t)mEntries.size();
270                 ct --;
271             }
272         }
273     }
274 }
275 
cleanupAll()276 void RsdShaderCache::cleanupAll() {
277     for (uint32_t ct=0; ct < mEntries.size(); ct++) {
278         glDeleteProgram(mEntries[ct]->program);
279         free(mEntries[ct]);
280     }
281     mEntries.clear();
282 }
283 
284