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