rsdShaderCache.cpp revision 7510992812e32c83114b98ea47fbb39876bdc223
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 27using namespace android; 28using namespace android::renderscript; 29 30 31RsdShaderCache::RsdShaderCache() { 32 mEntries.setCapacity(16); 33 mVertexDirty = true; 34 mFragmentDirty = true; 35} 36 37RsdShaderCache::~RsdShaderCache() { 38 cleanupAll(); 39} 40 41void 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 63void 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 70bool 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 86bool 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 107bool 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 //ALOGV("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 //ALOGV("SC using program %i", mEntries[ct]->program); 129 glUseProgram(mEntries[ct]->program); 130 mCurrent = mEntries[ct]; 131 //ALOGV("RsdShaderCache hit, using %i", ct); 132 rsdGLCheckError(rsc, "RsdShaderCache::link (hit)"); 133 return true; 134 } 135 } 136 137 //ALOGV("RsdShaderCache miss"); 138 //ALOGE("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 //ALOGE("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 //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, NULL, 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 = glGetAttribLocation(pgm, vtx->getAttribName(ct)); 180 e->vtxAttrs[ct].name = vtx->getAttribName(ct).string(); 181 if (rsc->props.mLogShaders) { 182 ALOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot); 183 } 184 } 185 186 populateUniformData(vtx, pgm, e->vtxUniforms); 187 populateUniformData(frag, pgm, e->fragUniforms); 188 189 // Only populate this list if we have arrays in our uniforms 190 UniformQueryData **uniformList = NULL; 191 GLint numUniforms = 0; 192 bool hasArrays = hasArrayUniforms(vtx, frag); 193 if (hasArrays) { 194 // Get the number of active uniforms and the length of the longest name 195 glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms); 196 GLint maxNameLength = 0; 197 glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); 198 if (numUniforms > 0 && maxNameLength > 0) { 199 uniformList = new UniformQueryData*[numUniforms]; 200 // Iterate over all the uniforms and build the list we 201 // can later use to match our uniforms to 202 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { 203 uniformList[ct] = new UniformQueryData(maxNameLength); 204 glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength, 205 &uniformList[ct]->arraySize, &uniformList[ct]->type, 206 uniformList[ct]->name); 207 //ALOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct, 208 // uniformList[ct]->arraySize, uniformList[ct]->name); 209 } 210 } 211 } 212 213 // We now know the highest index of all of the array uniforms 214 // and we need to update our cache to reflect that 215 // we may have declared [n], but only m < n elements are used 216 updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx", 217 uniformList, (uint32_t)numUniforms); 218 updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag", 219 uniformList, (uint32_t)numUniforms); 220 221 // Clean up the uniform data from GL 222 if (uniformList != NULL) { 223 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) { 224 delete uniformList[ct]; 225 } 226 delete[] uniformList; 227 uniformList = NULL; 228 } 229 } 230 231 //ALOGV("SC made program %i", e->program); 232 glUseProgram(e->program); 233 rsdGLCheckError(rsc, "RsdShaderCache::link (miss)"); 234 235 return true; 236} 237 238int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const { 239 for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { 240 if (attrName == mCurrent->vtxAttrs[ct].name) { 241 return mCurrent->vtxAttrs[ct].slot; 242 } 243 } 244 return -1; 245} 246 247void RsdShaderCache::cleanupVertex(uint32_t id) { 248 int32_t numEntries = (int32_t)mEntries.size(); 249 for (int32_t ct = 0; ct < numEntries; ct ++) { 250 if (mEntries[ct]->vtx == id) { 251 glDeleteProgram(mEntries[ct]->program); 252 253 delete mEntries[ct]; 254 mEntries.removeAt(ct); 255 numEntries = (int32_t)mEntries.size(); 256 ct --; 257 } 258 } 259} 260 261void RsdShaderCache::cleanupFragment(uint32_t id) { 262 int32_t numEntries = (int32_t)mEntries.size(); 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 275void RsdShaderCache::cleanupAll() { 276 for (uint32_t ct=0; ct < mEntries.size(); ct++) { 277 glDeleteProgram(mEntries[ct]->program); 278 free(mEntries[ct]); 279 } 280 mEntries.clear(); 281} 282 283