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