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