Home | History | Annotate | Download | only in driver
      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 
     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              LOGV("%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     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     //LOGV("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             //LOGV("SC using program %i", mEntries[ct]->program);
    129             glUseProgram(mEntries[ct]->program);
    130             mCurrent = mEntries[ct];
    131             //LOGV("RsdShaderCache hit, using %i", ct);
    132             rsdGLCheckError(rsc, "RsdShaderCache::link (hit)");
    133             return true;
    134         }
    135     }
    136 
    137     //LOGV("RsdShaderCache miss");
    138     //LOGE("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         //LOGE("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         //LOGE("e2 %x", glGetError());
    159         glLinkProgram(pgm);
    160         //LOGE("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                     LOGE("Could not link program:\n%s\n", buf);
    171                     free(buf);
    172                 }
    173             }
    174             glDeleteProgram(pgm);
    175             rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
    176             return false;
    177         }
    178 
    179         for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) {
    180             e->vtxAttrs[ct].slot = glGetAttribLocation(pgm, vtx->getAttribName(ct));
    181             e->vtxAttrs[ct].name = vtx->getAttribName(ct).string();
    182             if (rsc->props.mLogShaders) {
    183                 LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->vtxAttrs[ct].slot);
    184             }
    185         }
    186 
    187         populateUniformData(vtx, pgm, e->vtxUniforms);
    188         populateUniformData(frag, pgm, e->fragUniforms);
    189 
    190         // Only populate this list if we have arrays in our uniforms
    191         UniformQueryData **uniformList = NULL;
    192         GLint numUniforms = 0;
    193         bool hasArrays = hasArrayUniforms(vtx, frag);
    194         if (hasArrays) {
    195             // Get the number of active uniforms and the length of the longest name
    196             glGetProgramiv(pgm, GL_ACTIVE_UNIFORMS, &numUniforms);
    197             GLint maxNameLength = 0;
    198             glGetProgramiv(pgm, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
    199             if (numUniforms > 0 && maxNameLength > 0) {
    200                 uniformList = new UniformQueryData*[numUniforms];
    201                 // Iterate over all the uniforms and build the list we
    202                 // can later use to match our uniforms to
    203                 for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
    204                     uniformList[ct] = new UniformQueryData(maxNameLength);
    205                     glGetActiveUniform(pgm, ct, maxNameLength, &uniformList[ct]->writtenLength,
    206                                        &uniformList[ct]->arraySize, &uniformList[ct]->type,
    207                                        uniformList[ct]->name);
    208                     //LOGE("GL UNI idx=%u, arraySize=%u, name=%s", ct,
    209                     //     uniformList[ct]->arraySize, uniformList[ct]->name);
    210                 }
    211             }
    212         }
    213 
    214         // We now know the highest index of all of the array uniforms
    215         // and we need to update our cache to reflect that
    216         // we may have declared [n], but only m < n elements are used
    217         updateUniformArrayData(rsc, vtx, pgm, e->vtxUniforms, "vtx",
    218                                uniformList, (uint32_t)numUniforms);
    219         updateUniformArrayData(rsc, frag, pgm, e->fragUniforms, "frag",
    220                                uniformList, (uint32_t)numUniforms);
    221 
    222         // Clean up the uniform data from GL
    223         if (uniformList != NULL) {
    224             for (uint32_t ct = 0; ct < (uint32_t)numUniforms; ct++) {
    225                 delete uniformList[ct];
    226             }
    227             delete[] uniformList;
    228             uniformList = NULL;
    229         }
    230     }
    231 
    232     //LOGV("SC made program %i", e->program);
    233     glUseProgram(e->program);
    234     rsdGLCheckError(rsc, "RsdShaderCache::link (miss)");
    235 
    236     return true;
    237 }
    238 
    239 int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
    240     for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
    241         if (attrName == mCurrent->vtxAttrs[ct].name) {
    242             return mCurrent->vtxAttrs[ct].slot;
    243         }
    244     }
    245     return -1;
    246 }
    247 
    248 void RsdShaderCache::cleanupVertex(uint32_t id) {
    249     int32_t numEntries = (int32_t)mEntries.size();
    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.removeAt(ct);
    256             numEntries = (int32_t)mEntries.size();
    257             ct --;
    258         }
    259     }
    260 }
    261 
    262 void RsdShaderCache::cleanupFragment(uint32_t id) {
    263     int32_t numEntries = (int32_t)mEntries.size();
    264     for (int32_t ct = 0; ct < numEntries; ct ++) {
    265         if (mEntries[ct]->frag == id) {
    266             glDeleteProgram(mEntries[ct]->program);
    267 
    268             delete mEntries[ct];
    269             mEntries.removeAt(ct);
    270             numEntries = (int32_t)mEntries.size();
    271             ct --;
    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