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