rsdShaderCache.cpp revision a04e30dbb5ab11592b03666bb3d102070759c58e
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 23#include <GLES/gl.h> 24#include <GLES2/gl2.h> 25 26using namespace android; 27using namespace android::renderscript; 28 29 30RsdShaderCache::RsdShaderCache() { 31 mEntries.setCapacity(16); 32 mVertexDirty = true; 33 mFragmentDirty = true; 34} 35 36RsdShaderCache::~RsdShaderCache() { 37 cleanupAll(); 38} 39 40void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID, 41 UniformData *data, const char* logTag, 42 UniformQueryData **uniformList, uint32_t uniListSize) { 43 44 for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { 45 if (data[ct].slot >= 0 && data[ct].arraySize > 1) { 46 //Iterate over the list of active GL uniforms and find highest array index 47 for (uint32_t ui = 0; ui < uniListSize; ui ++) { 48 if (prog->getUniformName(ct) == uniformList[ui]->name) { 49 data[ct].arraySize = (uint32_t)uniformList[ui]->arraySize; 50 break; 51 } 52 } 53 } 54 55 if (rsc->props.mLogShaders) { 56 LOGV("%s U, %s = %d, arraySize = %d\n", logTag, 57 prog->getUniformName(ct).string(), data[ct].slot, data[ct].arraySize); 58 } 59 } 60} 61 62void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) { 63 for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { 64 data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct)); 65 data[ct].arraySize = prog->getUniformArraySize(ct); 66 } 67} 68 69bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) { 70 UniformData *data = mCurrent->vtxUniforms; 71 for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { 72 if (data[ct].slot >= 0 && data[ct].arraySize > 1) { 73 return true; 74 } 75 } 76 data = mCurrent->fragUniforms; 77 for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) { 78 if (data[ct].slot >= 0 && data[ct].arraySize > 1) { 79 return true; 80 } 81 } 82 return false; 83} 84 85bool RsdShaderCache::setup(const Context *rsc) { 86 if (!mVertexDirty && !mFragmentDirty) { 87 return true; 88 } 89 90 if (!link(rsc)) { 91 return false; 92 } 93 94 if (mFragmentDirty) { 95 mFragment->setup(rsc, this); 96 mFragmentDirty = false; 97 } 98 if (mVertexDirty) { 99 mVertex->setup(rsc, this); 100 mVertexDirty = false; 101 } 102 103 return true; 104} 105 106bool RsdShaderCache::link(const Context *rsc) { 107 108 RsdShader *vtx = mVertex; 109 RsdShader *frag = mFragment; 110 if (!vtx->getShaderID()) { 111 vtx->loadShader(rsc); 112 } 113 if (!frag->getShaderID()) { 114 frag->loadShader(rsc); 115 } 116 117 // Don't try to cache if shaders failed to load 118 if (!vtx->getShaderID() || !frag->getShaderID()) { 119 return false; 120 } 121 //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); 122 uint32_t entryCount = mEntries.size(); 123 for (uint32_t ct = 0; ct < entryCount; ct ++) { 124 if ((mEntries[ct]->vtx == vtx->getShaderID()) && 125 (mEntries[ct]->frag == frag->getShaderID())) { 126 127 //LOGV("SC using program %i", mEntries[ct]->program); 128 glUseProgram(mEntries[ct]->program); 129 mCurrent = mEntries[ct]; 130 //LOGV("RsdShaderCache hit, using %i", ct); 131 rsc->checkError("RsdShaderCache::link (hit)"); 132 return true; 133 } 134 } 135 136 //LOGV("RsdShaderCache miss"); 137 //LOGE("e0 %x", glGetError()); 138 ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(), 139 vtx->getUniformCount(), 140 frag->getUniformCount()); 141 mEntries.push(e); 142 mCurrent = e; 143 e->vtx = vtx->getShaderID(); 144 e->frag = frag->getShaderID(); 145 e->program = glCreateProgram(); 146 if (e->program) { 147 GLuint pgm = e->program; 148 glAttachShader(pgm, vtx->getShaderID()); 149 //LOGE("e1 %x", glGetError()); 150 glAttachShader(pgm, frag->getShaderID()); 151 152 glBindAttribLocation(pgm, 0, "ATTRIB_position"); 153 glBindAttribLocation(pgm, 1, "ATTRIB_color"); 154 glBindAttribLocation(pgm, 2, "ATTRIB_normal"); 155 glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); 156 157 //LOGE("e2 %x", glGetError()); 158 glLinkProgram(pgm); 159 //LOGE("e3 %x", glGetError()); 160 GLint linkStatus = GL_FALSE; 161 glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus); 162 if (linkStatus != GL_TRUE) { 163 GLint bufLength = 0; 164 glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength); 165 if (bufLength) { 166 char* buf = (char*) malloc(bufLength); 167 if (buf) { 168 glGetProgramInfoLog(pgm, bufLength, NULL, buf); 169 LOGE("Could not link program:\n%s\n", buf); 170 free(buf); 171 } 172 } 173 glDeleteProgram(pgm); 174 rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs"); 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 LOGV("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 //LOGE("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 //LOGV("SC made program %i", e->program); 232 glUseProgram(e->program); 233 rsc->checkError("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