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