Home | History | Annotate | Download | only in driver
      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, 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 
     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 
    112     uint32_t vID = vtx->getStateBasedShaderID(rsc);
    113     uint32_t fID = frag->getStateBasedShaderID(rsc);
    114 
    115     // Don't try to cache if shaders failed to load
    116     if (!vID || !fID) {
    117         return false;
    118     }
    119     uint32_t entryCount = mEntries.size();
    120     for (uint32_t ct = 0; ct < entryCount; ct ++) {
    121         if ((mEntries[ct]->vtx == vID) && (mEntries[ct]->frag == fID)) {
    122 
    123             //ALOGV("SC using program %i", mEntries[ct]->program);
    124             glUseProgram(mEntries[ct]->program);
    125             mCurrent = mEntries[ct];
    126             //ALOGV("RsdShaderCache hit, using %i", ct);
    127             rsdGLCheckError(rsc, "RsdShaderCache::link (hit)");
    128             return true;
    129         }
    130     }
    131 
    132     ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
    133                                        vtx->getUniformCount(),
    134                                        frag->getUniformCount());
    135     mEntries.push(e);
    136     mCurrent = e;
    137     e->vtx = vID;
    138     e->frag = fID;
    139     e->program = glCreateProgram();
    140     if (e->program) {
    141         GLuint pgm = e->program;
    142         glAttachShader(pgm, vID);
    143         //ALOGE("e1 %x", glGetError());
    144         glAttachShader(pgm, fID);
    145 
    146         glBindAttribLocation(pgm, 0, "ATTRIB_position");
    147         glBindAttribLocation(pgm, 1, "ATTRIB_color");
    148         glBindAttribLocation(pgm, 2, "ATTRIB_normal");
    149         glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
    150 
    151         //ALOGE("e2 %x", glGetError());
    152         glLinkProgram(pgm);
    153         //ALOGE("e3 %x", glGetError());
    154         GLint linkStatus = GL_FALSE;
    155         glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus);
    156         if (linkStatus != GL_TRUE) {
    157             GLint bufLength = 0;
    158             glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength);
    159             if (bufLength) {
    160                 char* buf = (char*) malloc(bufLength);
    161                 if (buf) {
    162                     glGetProgramInfoLog(pgm, bufLength, NULL, buf);
    163                     rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
    164                     free(buf);
    165                 }
    166             }
    167             glDeleteProgram(pgm);
    168             return false;
    169         }
    170 
    171         for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) {
    172             e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct));
    173             e->vtxAttrs[ct].name = vtx->getAttribName(ct).string();
    174             if (rsc->props.mLogShaders) {
    175                 ALOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot);
    176             }
    177         }
    178 
    179         populateUniformData(vtx, pgm, e->vtxUniforms);
    180         populateUniformData(frag, pgm, e->fragUniforms);
    181 
    182         // Only populate this list if we have arrays in our uniforms
    183         UniformQueryData **uniformList = NULL;
    184         GLint numUniforms = 0;
    185         bool hasArrays = hasArrayUniforms(vtx, frag);
    186         if (hasArrays) {
    187             // Get the number of active uniforms and the length of the longest name
    188             glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms);
    189             GLint maxNameLength = 0;
    190             glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
    191             if (numUniforms > 0 && maxNameLength > 0) {
    192                 uniformList = new UniformQueryData*[numUniforms];
    193                 // Iterate over all the uniforms and build the list we
    194                 // can later use to match our uniforms to
    195                 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
    196                     uniformList[ct] = new UniformQueryData(maxNameLength);
    197                     glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength,
    198                                        &uniformList[ct]->arraySize, &uniformList[ct]->type,
    199                                        uniformList[ct]->name);
    200                     //ALOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct,
    201                     //     uniformList[ct]->arraySize, uniformList[ct]->name);
    202                 }
    203             }
    204         }
    205 
    206         // We now know the highest index of all of the array uniforms
    207         // and we need to update our cache to reflect that
    208         // we may have declared [n], but only m < n elements are used
    209         updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx",
    210                                uniformList, (uint32_t)numUniforms);
    211         updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag",
    212                                uniformList, (uint32_t)numUniforms);
    213 
    214         // Clean up the uniform data from GL
    215         if (uniformList != NULL) {
    216             for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
    217                 delete uniformList[ct];
    218             }
    219             delete[] uniformList;
    220             uniformList = NULL;
    221         }
    222     }
    223 
    224     //ALOGV("SC made program %i", e->program);
    225     glUseProgram(e->program);
    226     rsdGLCheckError(rsc, "RsdShaderCache::link (miss)");
    227 
    228     return true;
    229 }
    230 
    231 int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
    232     for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
    233         if (attrName == mCurrent->vtxAttrs[ct].name) {
    234             return mCurrent->vtxAttrs[ct].slot;
    235         }
    236     }
    237     return -1;
    238 }
    239 
    240 void RsdShaderCache::cleanupVertex(RsdShader *s) {
    241     int32_t numEntries = (int32_t)mEntries.size();
    242     uint32_t numShaderIDs = s->getStateBasedIDCount();
    243     for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
    244         uint32_t id = s->getStateBasedID(sId);
    245         for (int32_t ct = 0; ct < numEntries; ct ++) {
    246             if (mEntries[ct]->vtx == id) {
    247                 glDeleteProgram(mEntries[ct]->program);
    248 
    249                 delete mEntries[ct];
    250                 mEntries.removeAt(ct);
    251                 numEntries = (int32_t)mEntries.size();
    252                 ct --;
    253             }
    254         }
    255     }
    256 }
    257 
    258 void RsdShaderCache::cleanupFragment(RsdShader *s) {
    259     int32_t numEntries = (int32_t)mEntries.size();
    260     uint32_t numShaderIDs = s->getStateBasedIDCount();
    261     for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
    262         uint32_t id = s->getStateBasedID(sId);
    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 }
    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