| /* |
| * Copyright 2014 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/GrRenderTarget.h" |
| #include "src/gpu/GrShaderCaps.h" |
| #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
| #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
| #include "src/gpu/glsl/GrGLSLVarying.h" |
| |
| GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program) |
| : GrGLSLShaderBuilder(program) {} |
| |
| const char* GrGLSLFragmentShaderBuilder::dstColor() { |
| SkDEBUGCODE(fHasReadDstColorThisStage_DebugOnly = true;) |
| |
| const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps(); |
| if (shaderCaps->fbFetchSupport()) { |
| this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature, |
| shaderCaps->fbFetchExtensionString()); |
| |
| // Some versions of this extension string require declaring custom color output on ES 3.0+ |
| const char* fbFetchColorName = "sk_LastFragColor"; |
| if (shaderCaps->fbFetchNeedsCustomOutput()) { |
| this->enableCustomOutput(); |
| fCustomColorOutput->setTypeModifier(GrShaderVar::TypeModifier::InOut); |
| fbFetchColorName = DeclaredColorOutputName(); |
| // Set the dstColor to an intermediate variable so we don't override it with the output |
| this->codeAppendf("half4 %s = %s;", kDstColorName, fbFetchColorName); |
| } else { |
| return fbFetchColorName; |
| } |
| } |
| return kDstColorName; |
| } |
| |
| void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) { |
| SkASSERT(GrBlendEquationIsAdvanced(equation)); |
| |
| if (fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs()) { |
| this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature, |
| "GL_KHR_blend_equation_advanced"); |
| this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier); |
| } |
| } |
| |
| void GrGLSLFragmentShaderBuilder::enableCustomOutput() { |
| if (!fCustomColorOutput) { |
| fCustomColorOutput = &fOutputs.emplace_back(DeclaredColorOutputName(), SkSLType::kHalf4, |
| GrShaderVar::TypeModifier::Out); |
| fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back()); |
| } |
| } |
| |
| void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() { |
| SkASSERT(!fHasSecondaryOutput); |
| fHasSecondaryOutput = true; |
| const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); |
| if (const char* extension = caps.secondaryOutputExtensionString()) { |
| this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); |
| } |
| |
| // If the primary output is declared, we must declare also the secondary output |
| // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom |
| // output. The condition also co-incides with the condition in which GLSL ES 2.0 |
| // requires the built-in gl_SecondaryFragColorEXT, whereas 3.0 requires a custom output. |
| if (caps.mustDeclareFragmentShaderOutput()) { |
| fOutputs.emplace_back(DeclaredSecondaryColorOutputName(), SkSLType::kHalf4, |
| GrShaderVar::TypeModifier::Out); |
| fProgramBuilder->finalizeFragmentSecondaryColor(fOutputs.back()); |
| } |
| } |
| |
| const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const { |
| return DeclaredColorOutputName(); |
| } |
| |
| bool GrGLSLFragmentShaderBuilder::primaryColorOutputIsInOut() const { |
| return fCustomColorOutput && |
| fCustomColorOutput->getTypeModifier() == GrShaderVar::TypeModifier::InOut; |
| } |
| |
| const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const { |
| if (this->hasSecondaryOutput()) { |
| return (fProgramBuilder->shaderCaps()->mustDeclareFragmentShaderOutput()) |
| ? DeclaredSecondaryColorOutputName() |
| : "sk_SecondaryFragColor"; |
| } |
| return nullptr; |
| } |
| |
| GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const { |
| return fProgramBuilder->origin(); |
| } |
| |
| void GrGLSLFragmentShaderBuilder::onFinalize() { |
| fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs()); |
| } |