rsdShader.cpp revision a04e30dbb5ab11592b03666bb3d102070759c58e
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 <GLES2/gl2.h> 18#include <GLES2/gl2ext.h> 19 20#include <rs_hal.h> 21#include <rsContext.h> 22#include <rsProgram.h> 23 24#include "rsdShader.h" 25#include "rsdShaderCache.h" 26 27using namespace android; 28using namespace android::renderscript; 29 30RsdShader::RsdShader(const Program *p, uint32_t type, 31 const char * shaderText, uint32_t shaderLength) { 32 33 mUserShader.setTo(shaderText, shaderLength); 34 mRSProgram = p; 35 mType = type; 36 initMemberVars(); 37 initAttribAndUniformArray(); 38 init(); 39} 40 41RsdShader::~RsdShader() { 42 if (mShaderID) { 43 glDeleteShader(mShaderID); 44 } 45 46 delete[] mAttribNames; 47 delete[] mUniformNames; 48 delete[] mUniformArraySizes; 49} 50 51void RsdShader::initMemberVars() { 52 mDirty = true; 53 mShaderID = 0; 54 mAttribCount = 0; 55 mUniformCount = 0; 56 57 mAttribNames = NULL; 58 mUniformNames = NULL; 59 mUniformArraySizes = NULL; 60 61 mIsValid = false; 62} 63 64void RsdShader::init() { 65 uint32_t attribCount = 0; 66 uint32_t uniformCount = 0; 67 for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { 68 initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); 69 } 70 for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { 71 initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); 72 } 73 74 mTextureUniformIndexStart = uniformCount; 75 char buf[256]; 76 for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { 77 snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); 78 mUniformNames[uniformCount].setTo(buf); 79 mUniformArraySizes[uniformCount] = 1; 80 uniformCount++; 81 } 82} 83 84String8 RsdShader::getGLSLInputString() const { 85 String8 s; 86 for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { 87 const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); 88 for (uint32_t field=0; field < e->getFieldCount(); field++) { 89 const Element *f = e->getField(field); 90 91 // Cannot be complex 92 rsAssert(!f->getFieldCount()); 93 switch (f->getComponent().getVectorSize()) { 94 case 1: s.append("attribute float ATTRIB_"); break; 95 case 2: s.append("attribute vec2 ATTRIB_"); break; 96 case 3: s.append("attribute vec3 ATTRIB_"); break; 97 case 4: s.append("attribute vec4 ATTRIB_"); break; 98 default: 99 rsAssert(0); 100 } 101 102 s.append(e->getFieldName(field)); 103 s.append(";\n"); 104 } 105 } 106 return s; 107} 108 109void RsdShader::appendAttributes() { 110 for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { 111 const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); 112 for (uint32_t field=0; field < e->getFieldCount(); field++) { 113 const Element *f = e->getField(field); 114 const char *fn = e->getFieldName(field); 115 116 if (fn[0] == '#') { 117 continue; 118 } 119 120 // Cannot be complex 121 rsAssert(!f->getFieldCount()); 122 switch (f->getComponent().getVectorSize()) { 123 case 1: mShader.append("attribute float ATTRIB_"); break; 124 case 2: mShader.append("attribute vec2 ATTRIB_"); break; 125 case 3: mShader.append("attribute vec3 ATTRIB_"); break; 126 case 4: mShader.append("attribute vec4 ATTRIB_"); break; 127 default: 128 rsAssert(0); 129 } 130 131 mShader.append(fn); 132 mShader.append(";\n"); 133 } 134 } 135} 136 137void RsdShader::appendTextures() { 138 char buf[256]; 139 for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { 140 if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) { 141 snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); 142 } else { 143 snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); 144 } 145 mShader.append(buf); 146 } 147} 148 149bool RsdShader::createShader() { 150 151 if (mType == GL_FRAGMENT_SHADER) { 152 mShader.append("precision mediump float;\n"); 153 } 154 appendUserConstants(); 155 appendAttributes(); 156 appendTextures(); 157 158 mShader.append(mUserShader); 159 160 return true; 161} 162 163bool RsdShader::loadShader(const Context *rsc) { 164 mShaderID = glCreateShader(mType); 165 rsAssert(mShaderID); 166 167 if (rsc->props.mLogShaders) { 168 LOGV("Loading shader type %x, ID %i", mType, mShaderID); 169 LOGV("%s", mShader.string()); 170 } 171 172 if (mShaderID) { 173 const char * ss = mShader.string(); 174 glShaderSource(mShaderID, 1, &ss, NULL); 175 glCompileShader(mShaderID); 176 177 GLint compiled = 0; 178 glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); 179 if (!compiled) { 180 GLint infoLen = 0; 181 glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); 182 if (infoLen) { 183 char* buf = (char*) malloc(infoLen); 184 if (buf) { 185 glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); 186 LOGE("Could not compile shader \n%s\n", buf); 187 free(buf); 188 } 189 glDeleteShader(mShaderID); 190 mShaderID = 0; 191 rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); 192 return false; 193 } 194 } 195 } 196 197 if (rsc->props.mLogShaders) { 198 LOGV("--Shader load result %x ", glGetError()); 199 } 200 mIsValid = true; 201 return true; 202} 203 204void RsdShader::appendUserConstants() { 205 for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { 206 const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); 207 for (uint32_t field=0; field < e->getFieldCount(); field++) { 208 const Element *f = e->getField(field); 209 const char *fn = e->getFieldName(field); 210 211 if (fn[0] == '#') { 212 continue; 213 } 214 215 // Cannot be complex 216 rsAssert(!f->getFieldCount()); 217 if (f->getType() == RS_TYPE_MATRIX_4X4) { 218 mShader.append("uniform mat4 UNI_"); 219 } else if (f->getType() == RS_TYPE_MATRIX_3X3) { 220 mShader.append("uniform mat3 UNI_"); 221 } else if (f->getType() == RS_TYPE_MATRIX_2X2) { 222 mShader.append("uniform mat2 UNI_"); 223 } else { 224 switch (f->getComponent().getVectorSize()) { 225 case 1: mShader.append("uniform float UNI_"); break; 226 case 2: mShader.append("uniform vec2 UNI_"); break; 227 case 3: mShader.append("uniform vec3 UNI_"); break; 228 case 4: mShader.append("uniform vec4 UNI_"); break; 229 default: 230 rsAssert(0); 231 } 232 } 233 234 mShader.append(fn); 235 if (e->getFieldArraySize(field) > 1) { 236 mShader.appendFormat("[%d]", e->getFieldArraySize(field)); 237 } 238 mShader.append(";\n"); 239 } 240 } 241} 242 243void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { 244 RsDataType dataType = field->getType(); 245 uint32_t elementSize = field->getSizeBytes() / sizeof(float); 246 for (uint32_t i = 0; i < arraySize; i ++) { 247 if (arraySize > 1) { 248 LOGV("Array Element [%u]", i); 249 } 250 if (dataType == RS_TYPE_MATRIX_4X4) { 251 LOGV("Matrix4x4"); 252 LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); 253 LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); 254 LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); 255 LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); 256 } else if (dataType == RS_TYPE_MATRIX_3X3) { 257 LOGV("Matrix3x3"); 258 LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); 259 LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); 260 LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); 261 } else if (dataType == RS_TYPE_MATRIX_2X2) { 262 LOGV("Matrix2x2"); 263 LOGV("{%f, %f", fd[0], fd[2]); 264 LOGV(" %f, %f}", fd[1], fd[3]); 265 } else { 266 switch (field->getComponent().getVectorSize()) { 267 case 1: 268 LOGV("Uniform 1 = %f", fd[0]); 269 break; 270 case 2: 271 LOGV("Uniform 2 = %f %f", fd[0], fd[1]); 272 break; 273 case 3: 274 LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); 275 break; 276 case 4: 277 LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); 278 break; 279 default: 280 rsAssert(0); 281 } 282 } 283 LOGE("Element size %u data=%p", elementSize, fd); 284 fd += elementSize; 285 LOGE("New data=%p", fd); 286 } 287} 288 289void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd, 290 int32_t slot, uint32_t arraySize ) { 291 RsDataType dataType = field->getType(); 292 if (dataType == RS_TYPE_MATRIX_4X4) { 293 glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); 294 } else if (dataType == RS_TYPE_MATRIX_3X3) { 295 glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); 296 } else if (dataType == RS_TYPE_MATRIX_2X2) { 297 glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); 298 } else { 299 switch (field->getComponent().getVectorSize()) { 300 case 1: 301 glUniform1fv(slot, arraySize, fd); 302 break; 303 case 2: 304 glUniform2fv(slot, arraySize, fd); 305 break; 306 case 3: 307 glUniform3fv(slot, arraySize, fd); 308 break; 309 case 4: 310 glUniform4fv(slot, arraySize, fd); 311 break; 312 default: 313 rsAssert(0); 314 } 315 } 316} 317 318void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) { 319 if (mRSProgram->mHal.state.texturesCount == 0) { 320 return; 321 } 322 323 uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount; 324 uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures(); 325 if (numTexturesToBind >= numTexturesAvailable) { 326 LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", 327 mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable); 328 rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); 329 numTexturesToBind = numTexturesAvailable; 330 } 331 332 for (uint32_t ct=0; ct < numTexturesToBind; ct++) { 333 glActiveTexture(GL_TEXTURE0 + ct); 334 if (!mRSProgram->mHal.state.textures[ct].get()) { 335 LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); 336 rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); 337 continue; 338 } 339 340 GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget(); 341 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { 342 LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); 343 rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); 344 } 345 glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID()); 346 rsc->checkError("ProgramFragment::setupGL2 tex bind"); 347 if (mRSProgram->mHal.state.samplers[ct].get()) { 348 mRSProgram->mHal.state.samplers[ct]->setupGL(rsc, mRSProgram->mHal.state.textures[ct].get()); 349 } else { 350 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 351 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 352 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 353 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 354 rsc->checkError("ProgramFragment::setupGL2 tex env"); 355 } 356 357 glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); 358 rsc->checkError("ProgramFragment::setupGL2 uniforms"); 359 } 360 361 glActiveTexture(GL_TEXTURE0); 362 mDirty = false; 363 rsc->checkError("ProgramFragment::setupGL2"); 364} 365 366void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) { 367 uint32_t uidx = 0; 368 for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { 369 Allocation *alloc = mRSProgram->mHal.state.constants[ct].get(); 370 if (!alloc) { 371 LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); 372 rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); 373 continue; 374 } 375 376 const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); 377 const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); 378 for (uint32_t field=0; field < e->getFieldCount(); field++) { 379 const Element *f = e->getField(field); 380 const char *fieldName = e->getFieldName(field); 381 // If this field is padding, skip it 382 if (fieldName[0] == '#') { 383 continue; 384 } 385 386 uint32_t offset = e->getFieldOffsetBytes(field); 387 const float *fd = reinterpret_cast<const float *>(&data[offset]); 388 389 int32_t slot = -1; 390 uint32_t arraySize = 1; 391 if (!isFragment) { 392 slot = sc->vtxUniformSlot(uidx); 393 arraySize = sc->vtxUniformSize(uidx); 394 } else { 395 slot = sc->fragUniformSlot(uidx); 396 arraySize = sc->fragUniformSize(uidx); 397 } 398 if (rsc->props.mLogShadersUniforms) { 399 LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); 400 } 401 uidx ++; 402 if (slot < 0) { 403 continue; 404 } 405 406 if (rsc->props.mLogShadersUniforms) { 407 logUniform(f, fd, arraySize); 408 } 409 setUniform(rsc, f, fd, slot, arraySize); 410 } 411 } 412} 413 414void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) { 415 416 setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER); 417 setupTextures(rsc, sc); 418} 419 420void RsdShader::initAttribAndUniformArray() { 421 mAttribCount = 0; 422 for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { 423 const Element *elem = mRSProgram->mHal.state.inputElements[ct].get(); 424 for (uint32_t field=0; field < elem->getFieldCount(); field++) { 425 if (elem->getFieldName(field)[0] != '#') { 426 mAttribCount ++; 427 } 428 } 429 } 430 431 mUniformCount = 0; 432 for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { 433 const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement(); 434 435 for (uint32_t field=0; field < elem->getFieldCount(); field++) { 436 if (elem->getFieldName(field)[0] != '#') { 437 mUniformCount ++; 438 } 439 } 440 } 441 mUniformCount += mRSProgram->mHal.state.texturesCount; 442 443 if (mAttribCount) { 444 mAttribNames = new String8[mAttribCount]; 445 } 446 if (mUniformCount) { 447 mUniformNames = new String8[mUniformCount]; 448 mUniformArraySizes = new uint32_t[mUniformCount]; 449 } 450} 451 452void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { 453 rsAssert(e->getFieldCount()); 454 for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { 455 const Element *ce = e->getField(ct); 456 if (ce->getFieldCount()) { 457 initAddUserElement(ce, names, arrayLengths, count, prefix); 458 } else if (e->getFieldName(ct)[0] != '#') { 459 String8 tmp(prefix); 460 tmp.append(e->getFieldName(ct)); 461 names[*count].setTo(tmp.string()); 462 if (arrayLengths) { 463 arrayLengths[*count] = e->getFieldArraySize(ct); 464 } 465 (*count)++; 466 } 467 } 468} 469