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