1 /* 2 * Copyright (C) 2011 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, 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 LOGV("%s U, %s = %d, arraySize = %d\n", logTag, 58 prog->getUniformName(ct).string(), data[ct].slot, data[ct].arraySize); 59 } 60 } 61 } 62 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 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 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 107 bool RsdShaderCache::link(const Context *rsc) { 108 109 RsdShader *vtx = mVertex; 110 RsdShader *frag = mFragment; 111 if (!vtx->getShaderID()) { 112 vtx->loadShader(rsc); 113 } 114 if (!frag->getShaderID()) { 115 frag->loadShader(rsc); 116 } 117 118 // Don't try to cache if shaders failed to load 119 if (!vtx->getShaderID() || !frag->getShaderID()) { 120 return false; 121 } 122 //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); 123 uint32_t entryCount = mEntries.size(); 124 for (uint32_t ct = 0; ct < entryCount; ct ++) { 125 if ((mEntries[ct]->vtx == vtx->getShaderID()) && 126 (mEntries[ct]->frag == frag->getShaderID())) { 127 128 //LOGV("SC using program %i", mEntries[ct]->program); 129 glUseProgram(mEntries[ct]->program); 130 mCurrent = mEntries[ct]; 131 //LOGV("RsdShaderCache hit, using %i", ct); 132 rsdGLCheckError(rsc, "RsdShaderCache::link (hit)"); 133 return true; 134 } 135 } 136 137 //LOGV("RsdShaderCache miss"); 138 //LOGE("e0 %x", glGetError()); 139 ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(), 140 vtx->getUniformCount(), 141 frag->getUniformCount()); 142 mEntries.push(e); 143 mCurrent = e; 144 e->vtx = vtx->getShaderID(); 145 e->frag = frag->getShaderID(); 146 e->program = glCreateProgram(); 147 if (e->program) { 148 GLuint pgm = e->program; 149 glAttachShader(pgm, vtx->getShaderID()); 150 //LOGE("e1 %x", glGetError()); 151 glAttachShader(pgm, frag->getShaderID()); 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 //LOGE("e2 %x", glGetError()); 159 glLinkProgram(pgm); 160 //LOGE("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, NULL, buf); 170 LOGE("Could not link program:\n%s\n", buf); 171 free(buf); 172 } 173 } 174 glDeleteProgram(pgm); 175 rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs"); 176 return false; 177 } 178 179 for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) { 180 e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct)); 181 e->vtxAttrs[ct].name = vtx->getAttribName(ct).string(); 182 if (rsc->props.mLogShaders) { 183 LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot); 184 } 185 } 186 187 populateUniformData(vtx, pgm, e->vtxUniforms); 188 populateUniformData(frag, pgm, e->fragUniforms); 189 190 // Only populate this list if we have arrays in our uniforms 191 UniformQueryData **uniformList = NULL; 192 GLint numUniforms = 0; 193 bool hasArrays = hasArrayUniforms(vtx, frag); 194 if (hasArrays) { 195 // Get the number of active uniforms and the length of the longest name 196 glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms); 197 GLint maxNameLength = 0; 198 glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); 199 if (numUniforms > 0 && maxNameLength > 0) { 200 uniformList = new UniformQueryData*[numUniforms]; 201 // Iterate over all the uniforms and build the list we 202 // can later use to match our uniforms to 203 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { 204 uniformList[ct] = new UniformQueryData(maxNameLength); 205 glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength, 206 &uniformList[ct]->arraySize, &uniformList[ct]->type, 207 uniformList[ct]->name); 208 //LOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct, 209 // uniformList[ct]->arraySize, uniformList[ct]->name); 210 } 211 } 212 } 213 214 // We now know the highest index of all of the array uniforms 215 // and we need to update our cache to reflect that 216 // we may have declared [n], but only m < n elements are used 217 updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx", 218 uniformList, (uint32_t)numUniforms); 219 updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag", 220 uniformList, (uint32_t)numUniforms); 221 222 // Clean up the uniform data from GL 223 if (uniformList != NULL) { 224 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { 225 delete uniformList[ct]; 226 } 227 delete[] uniformList; 228 uniformList = NULL; 229 } 230 } 231 232 //LOGV("SC made program %i", e->program); 233 glUseProgram(e->program); 234 rsdGLCheckError(rsc, "RsdShaderCache::link (miss)"); 235 236 return true; 237 } 238 239 int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const { 240 for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { 241 if (attrName == mCurrent->vtxAttrs[ct].name) { 242 return mCurrent->vtxAttrs[ct].slot; 243 } 244 } 245 return -1; 246 } 247 248 void RsdShaderCache::cleanupVertex(uint32_t id) { 249 int32_t numEntries = (int32_t)mEntries.size(); 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.removeAt(ct); 256 numEntries = (int32_t)mEntries.size(); 257 ct --; 258 } 259 } 260 } 261 262 void RsdShaderCache::cleanupFragment(uint32_t id) { 263 int32_t numEntries = (int32_t)mEntries.size(); 264 for (int32_t ct = 0; ct < numEntries; ct ++) { 265 if (mEntries[ct]->frag == id) { 266 glDeleteProgram(mEntries[ct]->program); 267 268 delete mEntries[ct]; 269 mEntries.removeAt(ct); 270 numEntries = (int32_t)mEntries.size(); 271 ct --; 272 } 273 } 274 } 275 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