1/* 2 * Copyright (C) 2009 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 "rsContext.h" 18 19#include <GLES/gl.h> 20#include <GLES2/gl2.h> 21 22using namespace android; 23using namespace android::renderscript; 24 25 26ShaderCache::ShaderCache() 27{ 28 mEntryCount = 0; 29 mEntryAllocationCount = 16; 30 mEntries = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t)); 31} 32 33ShaderCache::~ShaderCache() 34{ 35 for (uint32_t ct=0; ct < mEntryCount; ct++) { 36 glDeleteProgram(mEntries[ct].program); 37 } 38 39 mEntryCount = 0; 40 mEntryAllocationCount = 0; 41 free(mEntries); 42} 43 44bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) 45{ 46 if (!vtx->getShaderID()) { 47 vtx->loadShader(rsc); 48 } 49 if (!frag->getShaderID()) { 50 frag->loadShader(rsc); 51 } 52 //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); 53 54 for (uint32_t ct=0; ct < mEntryCount; ct++) { 55 if ((mEntries[ct].vtx == vtx->getShaderID()) && 56 (mEntries[ct].frag == frag->getShaderID())) { 57 58 //LOGV("SC using program %i", mEntries[ct].program); 59 glUseProgram(mEntries[ct].program); 60 mCurrent = &mEntries[ct]; 61 //LOGV("ShaderCache hit, using %i", ct); 62 rsc->checkError("ShaderCache::lookup (hit)"); 63 return true; 64 } 65 } 66 // Not in cache, add it. 67 68 if (mEntryAllocationCount == mEntryCount) { 69 // Out of space, make some. 70 mEntryAllocationCount *= 2; 71 entry_t *e = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t)); 72 if (!e) { 73 LOGE("Out of memory for ShaderCache::lookup"); 74 return false; 75 } 76 memcpy(e, mEntries, sizeof(entry_t) * mEntryCount); 77 free(mEntries); 78 mEntries = e; 79 } 80 81 //LOGV("ShaderCache miss, using %i", mEntryCount); 82 //LOGE("e0 %x", glGetError()); 83 84 entry_t *e = &mEntries[mEntryCount]; 85 mCurrent = e; 86 e->vtx = vtx->getShaderID(); 87 e->frag = frag->getShaderID(); 88 e->program = glCreateProgram(); 89 e->mUserVertexProgram = vtx->isUserProgram(); 90 if (mEntries[mEntryCount].program) { 91 GLuint pgm = e->program; 92 glAttachShader(pgm, vtx->getShaderID()); 93 //LOGE("e1 %x", glGetError()); 94 glAttachShader(pgm, frag->getShaderID()); 95 96 if (!vtx->isUserProgram()) { 97 glBindAttribLocation(pgm, 0, "ATTRIB_LegacyPosition"); 98 glBindAttribLocation(pgm, 1, "ATTRIB_LegacyColor"); 99 glBindAttribLocation(pgm, 2, "ATTRIB_LegacyNormal"); 100 glBindAttribLocation(pgm, 3, "ATTRIB_LegacyPointSize"); 101 glBindAttribLocation(pgm, 4, "ATTRIB_LegacyTexture"); 102 e->mVtxAttribSlots[RS_KIND_POSITION] = 0; 103 e->mVtxAttribSlots[RS_KIND_COLOR] = 1; 104 e->mVtxAttribSlots[RS_KIND_NORMAL] = 2; 105 e->mVtxAttribSlots[RS_KIND_POINT_SIZE] = 3; 106 e->mVtxAttribSlots[RS_KIND_TEXTURE] = 4; 107 } 108 109 //LOGE("e2 %x", glGetError()); 110 glLinkProgram(pgm); 111 //LOGE("e3 %x", glGetError()); 112 GLint linkStatus = GL_FALSE; 113 glGetProgramiv(pgm, GL_LINK_STATUS, &linkStatus); 114 if (linkStatus != GL_TRUE) { 115 GLint bufLength = 0; 116 glGetProgramiv(pgm, GL_INFO_LOG_LENGTH, &bufLength); 117 if (bufLength) { 118 char* buf = (char*) malloc(bufLength); 119 if (buf) { 120 glGetProgramInfoLog(pgm, bufLength, NULL, buf); 121 LOGE("Could not link program:\n%s\n", buf); 122 free(buf); 123 } 124 } 125 glDeleteProgram(pgm); 126 rsc->setError(RS_ERROR_BAD_SHADER, "Error linking GL Programs"); 127 return false; 128 } 129 if (vtx->isUserProgram()) { 130 for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) { 131 e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct)); 132 if (rsc->props.mLogShaders) { 133 LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]); 134 } 135 } 136 } 137 for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { 138 e->mVtxUniformSlots[ct] = glGetUniformLocation(pgm, vtx->getUniformName(ct)); 139 if (rsc->props.mLogShaders) { 140 LOGV("vtx U, %s = %d\n", vtx->getUniformName(ct).string(), e->mVtxUniformSlots[ct]); 141 } 142 } 143 for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) { 144 e->mFragUniformSlots[ct] = glGetUniformLocation(pgm, frag->getUniformName(ct)); 145 if (rsc->props.mLogShaders) { 146 LOGV("frag U, %s = %d\n", frag->getUniformName(ct).string(), e->mFragUniformSlots[ct]); 147 } 148 } 149 } 150 151 e->mIsValid = true; 152 //LOGV("SC made program %i", e->program); 153 glUseProgram(e->program); 154 mEntryCount++; 155 rsc->checkError("ShaderCache::lookup (miss)"); 156 return true; 157} 158 159void ShaderCache::cleanupVertex(uint32_t id) 160{ 161} 162 163void ShaderCache::cleanupFragment(uint32_t id) 164{ 165} 166 167void ShaderCache::cleanupAll() 168{ 169} 170 171