| /* | |
| * Copyright 2015 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/ganesh/glsl/GrGLSLVarying.h" | |
| #include "src/gpu/ganesh/GrGeometryProcessor.h" | |
| #include "src/gpu/ganesh/GrShaderCaps.h" | |
| #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h" | |
| #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h" | |
| #include "src/gpu/ganesh/glsl/GrGLSLShaderBuilder.h" | |
| #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h" | |
| #include "src/sksl/SkSLGLSL.h" | |
| void GrGLSLVaryingHandler::addPassThroughAttribute(const GrShaderVar& vsVar, | |
| const char* output, | |
| Interpolation interpolation) { | |
| SkASSERT(vsVar.getType() != SkSLType::kVoid); | |
| GrGLSLVarying v(vsVar.getType()); | |
| this->addVarying(vsVar.c_str(), &v, interpolation); | |
| fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), vsVar.c_str()); | |
| fProgramBuilder->fFS.codeAppendf("%s = %s;", output, v.fsIn()); | |
| } | |
| static bool use_flat_interpolation(GrGLSLVaryingHandler::Interpolation interpolation, | |
| const GrShaderCaps& shaderCaps) { | |
| switch (interpolation) { | |
| using Interpolation = GrGLSLVaryingHandler::Interpolation; | |
| case Interpolation::kInterpolated: | |
| return false; | |
| case Interpolation::kCanBeFlat: | |
| SkASSERT(!shaderCaps.fPreferFlatInterpolation || shaderCaps.fFlatInterpolationSupport); | |
| return shaderCaps.fPreferFlatInterpolation; | |
| case Interpolation::kMustBeFlat: | |
| SkASSERT(shaderCaps.fFlatInterpolationSupport); | |
| return true; | |
| } | |
| SK_ABORT("Invalid interpolation"); | |
| } | |
| void GrGLSLVaryingHandler::addVarying(const char* name, GrGLSLVarying* varying, | |
| Interpolation interpolation) { | |
| SkASSERT(SkSLTypeIsFloatType(varying->type()) || Interpolation::kMustBeFlat == interpolation); | |
| VaryingInfo& v = fVaryings.push_back(); | |
| SkASSERT(varying); | |
| SkASSERT(SkSLType::kVoid != varying->fType); | |
| v.fType = varying->fType; | |
| v.fIsFlat = use_flat_interpolation(interpolation, *fProgramBuilder->shaderCaps()); | |
| v.fVsOut = fProgramBuilder->nameVariable('v', name); | |
| v.fVisibility = kNone_GrShaderFlags; | |
| if (varying->isInVertexShader()) { | |
| varying->fVsOut = v.fVsOut.c_str(); | |
| v.fVisibility |= kVertex_GrShaderFlag; | |
| } | |
| if (varying->isInFragmentShader()) { | |
| varying->fFsIn = v.fVsOut.c_str(); | |
| v.fVisibility |= kFragment_GrShaderFlag; | |
| } | |
| } | |
| void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) { | |
| for (auto attr : gp.vertexAttributes()) { | |
| this->addAttribute(attr.asShaderVar()); | |
| } | |
| for (auto attr : gp.instanceAttributes()) { | |
| this->addAttribute(attr.asShaderVar()); | |
| } | |
| } | |
| void GrGLSLVaryingHandler::addAttribute(const GrShaderVar& var) { | |
| SkASSERT(GrShaderVar::TypeModifier::In == var.getTypeModifier()); | |
| for (const GrShaderVar& attr : fVertexInputs.items()) { | |
| // if attribute already added, don't add it again | |
| if (attr.getName().equals(var.getName())) { | |
| return; | |
| } | |
| } | |
| fVertexInputs.push_back(var); | |
| } | |
| void GrGLSLVaryingHandler::setNoPerspective() { | |
| const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); | |
| if (!caps.fNoPerspectiveInterpolationSupport) { | |
| return; | |
| } | |
| if (const char* extension = caps.noperspectiveInterpolationExtensionString()) { | |
| int bit = 1 << GrGLSLShaderBuilder::kNoPerspectiveInterpolation_GLSLPrivateFeature; | |
| fProgramBuilder->fVS.addFeature(bit, extension); | |
| fProgramBuilder->fFS.addFeature(bit, extension); | |
| } | |
| fDefaultInterpolationModifier = "noperspective"; | |
| } | |
| void GrGLSLVaryingHandler::finalize() { | |
| for (const VaryingInfo& v : fVaryings.items()) { | |
| const char* modifier = v.fIsFlat ? "flat" : fDefaultInterpolationModifier; | |
| if (v.fVisibility & kVertex_GrShaderFlag) { | |
| fVertexOutputs.emplace_back(v.fVsOut, v.fType, GrShaderVar::TypeModifier::Out, | |
| GrShaderVar::kNonArray, SkString(), SkString(modifier)); | |
| } | |
| if (v.fVisibility & kFragment_GrShaderFlag) { | |
| const char* fsIn = v.fVsOut.c_str(); | |
| fFragInputs.emplace_back(SkString(fsIn), v.fType, GrShaderVar::TypeModifier::In, | |
| GrShaderVar::kNonArray, SkString(), SkString(modifier)); | |
| } | |
| } | |
| this->onFinalize(); | |
| } | |
| void GrGLSLVaryingHandler::appendDecls(const VarArray& vars, SkString* out) const { | |
| for (const GrShaderVar& varying : vars.items()) { | |
| varying.appendDecl(fProgramBuilder->shaderCaps(), out); | |
| out->append(";"); | |
| } | |
| } | |
| void GrGLSLVaryingHandler::getVertexDecls(SkString* inputDecls, SkString* outputDecls) const { | |
| this->appendDecls(fVertexInputs, inputDecls); | |
| this->appendDecls(fVertexOutputs, outputDecls); | |
| } | |
| void GrGLSLVaryingHandler::getFragDecls(SkString* inputDecls, SkString* outputDecls) const { | |
| // We should not have any outputs in the fragment shader when using version 1.10 | |
| SkASSERT(SkSL::GLSLGeneration::k110 != fProgramBuilder->shaderCaps()->fGLSLGeneration || | |
| fFragOutputs.empty()); | |
| this->appendDecls(fFragInputs, inputDecls); | |
| this->appendDecls(fFragOutputs, outputDecls); | |
| } |