void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) { this->INHERITED::bindProgramLocations(programId); const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); // Bind the attrib locations to same values for all shaders SkASSERT(-1 != header.fPositionAttributeIndex); GL_CALL(BindAttribLocation(programId, header.fPositionAttributeIndex, fPositionVar->c_str())); if (-1 != header.fLocalCoordAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fLocalCoordAttributeIndex, fLocalCoordsVar->c_str())); } if (-1 != header.fColorAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fColorAttributeIndex, color_attribute_name())); } if (-1 != header.fCoverageAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fCoverageAttributeIndex, coverage_attribute_name())); } const AttributePair* attribEnd = fEffectAttributes.end(); for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str())); } }
void GrGLVertexShaderBuilder::bindProgramLocations(GrGLuint programId) { const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader(); GrGpuGL* gpu = fProgramBuilder->gpu(); // Bind the attrib locations to same values for all shaders SkASSERT(-1 != header.fPositionAttributeIndex); GL_CALL(BindAttribLocation(programId, header.fPositionAttributeIndex, fPositionVar->c_str())); if (-1 != header.fLocalCoordAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fLocalCoordAttributeIndex, fLocalCoordsVar->c_str())); } if (-1 != header.fColorAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fColorAttributeIndex, color_attribute_name())); } if (-1 != header.fCoverageAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fCoverageAttributeIndex, coverage_attribute_name())); } // We pull the current state of attributes off of drawstate's optimized state and bind them in // order. This assumes that the drawState has not changed since we called flushGraphicsState() // higher up in the stack. const GrDrawTargetCaps* caps = fProgramBuilder->gpu()->caps(); const GrDrawState& drawState = *fProgramBuilder->gpu()->drawState(); SkAutoTUnref<GrOptDrawState> optState(drawState.createOptState(*caps)); const GrVertexAttrib* vaPtr = optState->getVertexAttribs(); const int vaCount = optState->getVertexAttribCount(); int i = fEffectAttribOffset; for (int index = 0; index < vaCount; index++) { if (kGeometryProcessor_GrVertexAttribBinding != vaPtr[index].fBinding) { continue; } SkASSERT(index != header.fPositionAttributeIndex && index != header.fLocalCoordAttributeIndex && index != header.fColorAttributeIndex && index != header.fCoverageAttributeIndex); // We should never find another effect attribute if we have bound everything SkASSERT(i < fInputs.count()); GL_CALL(BindAttribLocation(programId, index, fInputs[i].c_str())); i++; } // Make sure we bound everything SkASSERT(fInputs.count() == i); }
bool NullTechnique::Init() { if (!Technique::Init()) { return false; } if (!AddShader(GL_VERTEX_SHADER, "shaders/null_technique.vs")) { return false; } if (!AddShader(GL_FRAGMENT_SHADER, "shaders/null_technique.fs")) { return false; } BindAttribLocation(0, "Position"); if (!Finalize()) { return false; } m_WVPLocation = GetUniformLocation("gWVP"); if (m_WVPLocation == INVALID_UNIFORM_LOCATION) { return false; } return true; }
void GrGLVertexBuilder::bindVertexAttributes(GrGLuint programID) { const GrPrimitiveProcessor& primProc = fProgramBuilder->primitiveProcessor(); int vaCount = primProc.numAttribs(); for (int i = 0; i < vaCount; i++) { GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); } return; }
void GrGLVertexBuilder::bindVertexAttributes(GrGLuint programID) { const GrGeometryProcessor* gp = fProgramBuilder->fOptState.getGeometryProcessor(); const GrGeometryProcessor::VertexAttribArray& v = gp->getAttribs(); int vaCount = v.count(); for (int i = 0; i < vaCount; i++) { GL_CALL(BindAttribLocation(programID, i, v[i].fName)); } return; }
bool LightingTechnique::Init() { if (!Technique::Init()) { return false; } if (!AddShader(GL_VERTEX_SHADER, "lighting.vs")) { return false; } if (!AddShader(GL_FRAGMENT_SHADER, "lighting.fs")) { return false; } if (!Finalize()) { return false; } BindAttribLocation(0, "Position"); BindAttribLocation(1, "TexCoord"); BindAttribLocation(2, "Normal"); m_WVPLocation = GetUniformLocation("gWVP"); m_WorldMatrixLocation = GetUniformLocation("gWorld"); m_samplerLocation = GetUniformLocation("gSampler"); m_dirLightLocation.Color = GetUniformLocation("gDirectionalLight.Color"); m_dirLightLocation.AmbientIntensity = GetUniformLocation("gDirectionalLight.AmbientIntensity"); m_dirLightLocation.Direction = GetUniformLocation("gDirectionalLight.Direction"); m_dirLightLocation.DiffuseIntensity = GetUniformLocation("gDirectionalLight.DiffuseIntensity"); if (m_dirLightLocation.AmbientIntensity == 0xFFFFFFFF || m_WVPLocation == 0xFFFFFFFF || m_WorldMatrixLocation == 0xFFFFFFFF || m_samplerLocation == 0xFFFFFFFF || m_dirLightLocation.Color == 0xFFFFFFFF || m_dirLightLocation.DiffuseIntensity == 0xFFFFFFFF || m_dirLightLocation.Direction == 0xFFFFFFFF) { return false; } return true; }
GrGLProgram* GrGLProgramBuilder::finalize() { // verify we can get a program id GrGLuint programID; GL_CALL_RET(programID, CreateProgram()); if (0 == programID) { this->cleanupFragmentProcessors(); return nullptr; } // compile shaders and bind attributes / uniforms SkTDArray<GrGLuint> shadersToDelete; fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } // NVPR actually requires a vertex shader to compile bool useNvpr = primitiveProcessor().isPathRendering(); if (!useNvpr) { const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); int vaCount = primProc.numAttribs(); for (int i = 0; i < vaCount; i++) { GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); } } fFS.finalize(GrGLSLUniformHandler::kFragment_Visibility); if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } this->bindProgramResourceLocations(programID); GL_CALL(LinkProgram(programID)); // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver(); #ifdef SK_DEBUG checkLinked = true; #endif if (checkLinked) { checkLinkStatus(programID); } this->resolveProgramResourceLocations(programID); this->cleanupShaders(shadersToDelete); return this->createProgram(programID); }
GrGLProgram* GrGLProgramBuilder::finalize() { TRACE_EVENT0("skia", TRACE_FUNC); // verify we can get a program id GrGLuint programID; GL_CALL_RET(programID, CreateProgram()); if (0 == programID) { this->cleanupFragmentProcessors(); return nullptr; } if (this->gpu()->glCaps().programBinarySupport() && this->gpu()->getContext()->contextPriv().getPersistentCache()) { GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE)); } this->finalizeShaders(); // compile shaders and bind attributes / uniforms const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); SkSL::Program::Settings settings; settings.fCaps = this->gpu()->glCaps().shaderCaps(); settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin; settings.fSharpenTextures = this->gpu()->getContext()->contextPriv().sharpenMipmappedTextures(); SkSL::Program::Inputs inputs; SkTDArray<GrGLuint> shadersToDelete; bool cached = fGpu->glCaps().programBinarySupport() && nullptr != fCached.get(); if (cached) { this->bindProgramResourceLocations(programID); // cache hit, just hand the binary to GL const uint8_t* bytes = fCached->bytes(); size_t offset = 0; memcpy(&inputs, bytes + offset, sizeof(inputs)); offset += sizeof(inputs); int binaryFormat; memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat)); offset += sizeof(binaryFormat); GrGLClearErr(this->gpu()->glInterface()); GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(), ProgramBinary(programID, binaryFormat, (void*) (bytes + offset), fCached->size() - offset)); if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) { if (inputs.fRTHeight) { this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); } cached = this->checkLinkStatus(programID); } else { cached = false; } } if (!cached) { // cache miss, compile shaders if (fFS.fForceHighPrecision) { settings.fForceHighPrecision = true; } SkSL::String glsl; std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(), fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(), settings, &glsl); inputs = fs->fInputs; if (inputs.fRTHeight) { this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); } if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings, inputs)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(), fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(), settings, &glsl); if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, GR_GL_VERTEX_SHADER, &shadersToDelete, settings, inputs)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } // NVPR actually requires a vertex shader to compile bool useNvpr = primProc.isPathRendering(); if (!useNvpr) { int vaCount = primProc.numAttribs(); for (int i = 0; i < vaCount; i++) { GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); } } if (primProc.willUseGeoShader()) { std::unique_ptr<SkSL::Program> gs; gs = GrSkSLtoGLSL(gpu()->glContext(), GR_GL_GEOMETRY_SHADER, fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(), fGS.fCompilerStrings.count(), settings, &glsl); if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete, settings, inputs)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; } } this->bindProgramResourceLocations(programID); GL_CALL(LinkProgram(programID)); } // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver(); #ifdef SK_DEBUG checkLinked = true; #endif if (checkLinked) { if (!this->checkLinkStatus(programID)) { SkDebugf("VS:\n"); GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(), fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(), settings); if (primProc.willUseGeoShader()) { SkDebugf("\nGS:\n"); GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER, fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(), fGS.fCompilerStrings.count(), settings); } SkDebugf("\nFS:\n"); GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(), fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(), settings); SkDEBUGFAIL(""); return nullptr; } } this->resolveProgramResourceLocations(programID); this->cleanupShaders(shadersToDelete); if (!cached && this->gpu()->getContext()->contextPriv().getPersistentCache() && fGpu->glCaps().programBinarySupport()) { GrGLsizei length = 0; GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length)); if (length > 0) { // store shader in cache sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength()); GrGLenum binaryFormat; std::unique_ptr<char[]> binary(new char[length]); GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get())); size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length; std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]); size_t offset = 0; memcpy(data.get() + offset, &inputs, sizeof(inputs)); offset += sizeof(inputs); memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat)); offset += sizeof(binaryFormat); memcpy(data.get() + offset, binary.get(), length); this->gpu()->getContext()->contextPriv().getPersistentCache()->store( *key, *SkData::MakeWithoutCopy(data.get(), dataLength)); } } return this->createProgram(programID); }
bool LightingTechnique::Init() { if (!Technique::Init()) { return false; } if (!AddShader(GL_VERTEX_SHADER, "lighting.vs")) { return false; } if (!AddShader(GL_FRAGMENT_SHADER, "lighting.fs")) { return false; } BindAttribLocation(0, "Position"); BindAttribLocation(1, "TexCoord"); BindAttribLocation(2, "Normal"); if (!Finalize()) { return false; } m_WVPLocation = GetUniformLocation("gWVP"); m_LightWVPLocation = GetUniformLocation("gLightWVP"); m_WorldMatrixLocation = GetUniformLocation("gWorld"); m_samplerLocation = GetUniformLocation("gSampler"); m_shadowMapLocation = GetUniformLocation("gShadowMap"); m_eyeWorldPosLocation = GetUniformLocation("gEyeWorldPos"); m_dirLightLocation.Color = GetUniformLocation("gDirectionalLight.Base.Color"); m_dirLightLocation.AmbientIntensity = GetUniformLocation("gDirectionalLight.Base.AmbientIntensity"); m_dirLightLocation.Direction = GetUniformLocation("gDirectionalLight.Direction"); m_dirLightLocation.DiffuseIntensity = GetUniformLocation("gDirectionalLight.Base.DiffuseIntensity"); m_matSpecularIntensityLocation = GetUniformLocation("gMatSpecularIntensity"); m_matSpecularPowerLocation = GetUniformLocation("gSpecularPower"); m_numPointLightsLocation = GetUniformLocation("gNumPointLights"); m_numSpotLightsLocation = GetUniformLocation("gNumSpotLights"); if (m_dirLightLocation.AmbientIntensity == INVALID_UNIFORM_LOCATION || m_WVPLocation == INVALID_UNIFORM_LOCATION || m_LightWVPLocation == INVALID_UNIFORM_LOCATION || m_WorldMatrixLocation == INVALID_UNIFORM_LOCATION || m_samplerLocation == INVALID_UNIFORM_LOCATION || m_shadowMapLocation == INVALID_UNIFORM_LOCATION || m_eyeWorldPosLocation == INVALID_UNIFORM_LOCATION || m_dirLightLocation.Color == INVALID_UNIFORM_LOCATION || m_dirLightLocation.DiffuseIntensity == INVALID_UNIFORM_LOCATION || m_dirLightLocation.Direction == INVALID_UNIFORM_LOCATION || m_matSpecularIntensityLocation == INVALID_UNIFORM_LOCATION || m_matSpecularPowerLocation == INVALID_UNIFORM_LOCATION || m_numPointLightsLocation == INVALID_UNIFORM_LOCATION || m_numSpotLightsLocation == INVALID_UNIFORM_LOCATION) { return false; } for (unsigned int i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(m_pointLightsLocation) ; i++) { char Name[128]; memset(Name, 0, sizeof(Name)); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Base.Color", i); m_pointLightsLocation[i].Color = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Base.AmbientIntensity", i); m_pointLightsLocation[i].AmbientIntensity = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Position", i); m_pointLightsLocation[i].Position = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Base.DiffuseIntensity", i); m_pointLightsLocation[i].DiffuseIntensity = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Atten.Constant", i); m_pointLightsLocation[i].Atten.Constant = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Atten.Linear", i); m_pointLightsLocation[i].Atten.Linear = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gPointLights[%d].Atten.Exp", i); m_pointLightsLocation[i].Atten.Exp = GetUniformLocation(Name); if (m_pointLightsLocation[i].Color == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].AmbientIntensity == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].Position == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].DiffuseIntensity == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].Atten.Constant == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].Atten.Linear == INVALID_UNIFORM_LOCATION || m_pointLightsLocation[i].Atten.Exp == INVALID_UNIFORM_LOCATION) { return false; } } for (unsigned int i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(m_spotLightsLocation) ; i++) { char Name[128]; memset(Name, 0, sizeof(Name)); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Base.Color", i); m_spotLightsLocation[i].Color = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Base.AmbientIntensity", i); m_spotLightsLocation[i].AmbientIntensity = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Position", i); m_spotLightsLocation[i].Position = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Direction", i); m_spotLightsLocation[i].Direction = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Cutoff", i); m_spotLightsLocation[i].Cutoff = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Base.DiffuseIntensity", i); m_spotLightsLocation[i].DiffuseIntensity = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Atten.Constant", i); m_spotLightsLocation[i].Atten.Constant = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Atten.Linear", i); m_spotLightsLocation[i].Atten.Linear = GetUniformLocation(Name); SNPRINTF(Name, sizeof(Name), "gSpotLights[%d].Base.Atten.Exp", i); m_spotLightsLocation[i].Atten.Exp = GetUniformLocation(Name); if (m_spotLightsLocation[i].Color == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].AmbientIntensity == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Position == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Direction == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Cutoff == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].DiffuseIntensity == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Atten.Constant == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Atten.Linear == INVALID_UNIFORM_LOCATION || m_spotLightsLocation[i].Atten.Exp == INVALID_UNIFORM_LOCATION) { return false; } } return true; }
void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, const GrDrawTarget* target) const { ShaderCodeSegments segments; const uint32_t& layout = fProgramDesc.fVertexLayout; memset(&programData->fUniLocations, 0, sizeof(UniLocations)); bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit & fProgramDesc.fOptFlags); #if ATTRIBUTE_MATRIX segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"; #else segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n"; segments.fVSAttrs = ""; #endif segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n"; if (haveColor) { segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n"; segments.fVaryings = "varying vec4 vColor;\n"; } else { segments.fVaryings = ""; } segments.fVSCode = "void main() {\n" "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n" "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"; if (haveColor) { segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n"; } if (!(fProgramDesc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)) { segments.fVSCode += "\tgl_PointSize = 1.0;\n"; } segments.fFSCode = "void main() {\n"; // add texture coordinates that are used to the list of vertex attr decls GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords]; for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { if (target->VertexUsesTexCoordIdx(t, layout)) { tex_attr_name(t, texCoordAttrs + t); segments.fVSAttrs += "attribute vec2 "; segments.fVSAttrs += texCoordAttrs[t]; segments.fVSAttrs += ";\n"; } } // for each enabled stage figure out what the input coordinates are // and count the number of stages in use. const char* stageInCoords[GrDrawTarget::kNumStages]; int numActiveStages = 0; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { stageInCoords[s] = POS_ATTR_NAME; } else { int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); // we better have input tex coordinates if stage is enabled. GrAssert(tcIdx >= 0); GrAssert(texCoordAttrs[tcIdx].length()); stageInCoords[s] = texCoordAttrs[tcIdx].cstr(); } ++numActiveStages; } } GrTokenString inColor = "vColor"; // if we have active stages string them together, feeding the output color // of each to the next and generating code for each stage. if (numActiveStages) { int currActiveStage = 0; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { GrTokenString outColor; if (currActiveStage < (numActiveStages - 1)) { outColor = "color"; outColor.appendInt(currActiveStage); segments.fFSCode += "\tvec4 "; segments.fFSCode += outColor; segments.fFSCode += ";\n"; } else { outColor = "gl_FragColor"; } genStageCode(s, fProgramDesc.fStages[s], haveColor ? inColor.cstr() : NULL, outColor.cstr(), stageInCoords[s], &segments, &programData->fUniLocations.fStages[s]); ++currActiveStage; inColor = outColor; haveColor = true; } } } else { segments.fFSCode += "\tgl_FragColor = "; if (haveColor) { segments.fFSCode += inColor; } else { segments.fFSCode += "vec4(1,1,1,1)"; } segments.fFSCode += ";\n"; } segments.fFSCode += "}\n"; segments.fVSCode += "}\n"; const char* strings[4]; int lengths[4]; int stringCnt = 0; if (segments.fVSUnis.length()) { strings[stringCnt] = segments.fVSUnis.cstr(); lengths[stringCnt] = segments.fVSUnis.length(); ++stringCnt; } if (segments.fVSAttrs.length()) { strings[stringCnt] = segments.fVSAttrs.cstr(); lengths[stringCnt] = segments.fVSAttrs.length(); ++stringCnt; } if (segments.fVaryings.length()) { strings[stringCnt] = segments.fVaryings.cstr(); lengths[stringCnt] = segments.fVaryings.length(); ++stringCnt; } GrAssert(segments.fVSCode.length()); strings[stringCnt] = segments.fVSCode.cstr(); lengths[stringCnt] = segments.fVSCode.length(); ++stringCnt; #if PRINT_SHADERS GrPrintf("%s%s%s%s\n", segments.fVSUnis.cstr(), segments.fVSAttrs.cstr(), segments.fVaryings.cstr(), segments.fVSCode.cstr()); #endif programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, stringCnt, strings, lengths); stringCnt = 0; if (strlen(GrShaderPrecision()) > 1) { strings[stringCnt] = GrShaderPrecision(); lengths[stringCnt] = strlen(GrShaderPrecision()); ++stringCnt; } if (segments.fFSUnis.length()) { strings[stringCnt] = segments.fFSUnis.cstr(); lengths[stringCnt] = segments.fFSUnis.length(); ++stringCnt; } if (segments.fVaryings.length()) { strings[stringCnt] = segments.fVaryings.cstr(); lengths[stringCnt] = segments.fVaryings.length(); ++stringCnt; } GrAssert(segments.fFSCode.length()); strings[stringCnt] = segments.fFSCode.cstr(); lengths[stringCnt] = segments.fFSCode.length(); ++stringCnt; #if PRINT_SHADERS GrPrintf("%s%s%s%s\n", GR_SHADER_PRECISION, segments.fFSUnis.cstr(), segments.fVaryings.cstr(), segments.fFSCode.cstr()); #endif programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, stringCnt, strings, lengths); programData->fProgramID = GR_GL(CreateProgram()); const GrGLint& progID = programData->fProgramID; GR_GL(AttachShader(progID, programData->fVShaderID)); GR_GL(AttachShader(progID, programData->fFShaderID)); // Bind the attrib locations to same values for all shaders GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME)); for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { if (texCoordAttrs[t].length()) { GR_GL(BindAttribLocation(progID, TEX_ATTR_LOCATION(t), texCoordAttrs[t].cstr())); } } #if ATTRIBUTE_MATRIX // set unis to a bogus value so that checks against -1 before // flushing will pass. GR_GL(BindAttribLocation(progID, VIEWMAT_ATTR_LOCATION, VIEW_MATRIX_NAME)); program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION; for (int s = 0; s < kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { GrStringBuilder matName; tex_matrix_name(s, &matName); GR_GL(BindAttribLocation(progID, TEXMAT_ATTR_LOCATION(s), matName.cstr())); program->fUniLocations.fStages[s].fTextureMatrixUni = BOGUS_MATRIX_UNI_LOCATION; } } #endif GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME)); GR_GL(LinkProgram(progID)); GrGLint linked = GR_GL_INIT_ZERO; GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked)); if (!linked) { GrGLint infoLen = GR_GL_INIT_ZERO; GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen)); GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger if (infoLen > 0) { GR_GL(GetProgramInfoLog(progID, infoLen+1, NULL, (char*)log.get())); GrPrintf((char*)log.get()); } GrAssert(!"Error linking program"); GR_GL(DeleteProgram(progID)); programData->fProgramID = 0; return; } // Get uniform locations #if !ATTRIBUTE_MATRIX programData->fUniLocations.fViewMatrixUni = GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); GrAssert(-1 != programData->fUniLocations.fViewMatrixUni); #endif for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { StageUniLocations& locations = programData->fUniLocations.fStages[s]; if (fProgramDesc.fStages[s].fEnabled) { #if !ATTRIBUTE_MATRIX if (locations.fTextureMatrixUni) { GrTokenString texMName; tex_matrix_name(s, &texMName); locations.fTextureMatrixUni = GR_GL(GetUniformLocation( progID, texMName.cstr())); GrAssert(-1 != locations.fTextureMatrixUni); } else { locations.fTextureMatrixUni = -1; } #endif if (locations.fSamplerUni) { GrTokenString samplerName; sampler_name(s, &samplerName); locations.fSamplerUni = GR_GL(GetUniformLocation( progID, samplerName.cstr())); GrAssert(-1 != locations.fSamplerUni); } else { locations.fSamplerUni = -1; } if (locations.fRadial2Uni) { GrTokenString radial2ParamName; radial2_param_name(s, &radial2ParamName); locations.fRadial2Uni = GR_GL(GetUniformLocation( progID, radial2ParamName.cstr())); GrAssert(-1 != locations.fRadial2Uni); } else { locations.fRadial2Uni = -1; } } else { locations.fSamplerUni = -1; locations.fRadial2Uni = -1; locations.fTextureMatrixUni = -1; } } GR_GL(UseProgram(progID)); // init sampler unis and set bogus values for state tracking for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) { GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s)); } programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); programData->fRadial2CenterX1[s] = GR_ScalarMax; programData->fRadial2Radius0[s] = -GR_ScalarMax; } programData->fViewMatrix = GrMatrix::InvalidMatrix(); }