/* * 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/GrShaderCaps.h" #include "src/gpu/glsl/GrGLSLProgramBuilder.h" #include "src/gpu/glsl/GrGLSLVarying.h" void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::Attribute& input, const char* output, Interpolation interpolation) { SkASSERT(input.isInitialized()); SkASSERT(!fProgramBuilder->geometryProcessor().willUseGeoShader()); GrGLSLVarying v(input.gpuType()); this->addVarying(input.name(), &v, interpolation); fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), input.name()); 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.preferFlatInterpolation() || shaderCaps.flatInterpolationSupport()); return shaderCaps.preferFlatInterpolation(); case Interpolation::kMustBeFlat: SkASSERT(shaderCaps.flatInterpolationSupport()); return true; } SK_ABORT("Invalid interpolation"); } void GrGLSLVaryingHandler::addVarying(const char* name, GrGLSLVarying* varying, Interpolation interpolation) { SkASSERT(GrSLTypeIsFloatType(varying->type()) || Interpolation::kMustBeFlat == interpolation); bool willUseGeoShader = fProgramBuilder->geometryProcessor().willUseGeoShader(); VaryingInfo& v = fVaryings.push_back(); SkASSERT(varying); SkASSERT(kVoid_GrSLType != 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 (willUseGeoShader) { v.fGsOut = fProgramBuilder->nameVariable('g', name); varying->fGsIn = v.fVsOut.c_str(); varying->fGsOut = v.fGsOut.c_str(); v.fVisibility |= kGeometry_GrShaderFlag; } if (varying->isInFragmentShader()) { varying->fFsIn = (willUseGeoShader ? v.fGsOut : v.fVsOut).c_str(); v.fVisibility |= kFragment_GrShaderFlag; } } void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) { for (const auto& attr : gp.vertexAttributes()) { this->addAttribute(attr.asShaderVar()); } for (const 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.noperspectiveInterpolationSupport()) { return; } if (const char* extension = caps.noperspectiveInterpolationExtensionString()) { int bit = 1 << GrGLSLShaderBuilder::kNoPerspectiveInterpolation_GLSLPrivateFeature; fProgramBuilder->fVS.addFeature(bit, extension); if (fProgramBuilder->geometryProcessor().willUseGeoShader()) { fProgramBuilder->fGS.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 & kGeometry_GrShaderFlag) { fGeomInputs.emplace_back(v.fVsOut, v.fType, GrShaderVar::TypeModifier::In, GrShaderVar::kUnsizedArray, SkString(), SkString(modifier)); } } if (v.fVisibility & kFragment_GrShaderFlag) { const char* fsIn = v.fVsOut.c_str(); if (v.fVisibility & kGeometry_GrShaderFlag) { fGeomOutputs.emplace_back(v.fGsOut, v.fType, GrShaderVar::TypeModifier::Out, GrShaderVar::kNonArray, SkString(), SkString(modifier)); fsIn = v.fGsOut.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::getGeomDecls(SkString* inputDecls, SkString* outputDecls) const { this->appendDecls(fGeomInputs, inputDecls); this->appendDecls(fGeomOutputs, 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(k110_GrGLSLGeneration != fProgramBuilder->shaderCaps()->generation() || fFragOutputs.empty()); this->appendDecls(fFragInputs, inputDecls); this->appendDecls(fFragOutputs, outputDecls); }