blob: b766280d23aaa5dbcd7e81c25b4f73bad150ae44 [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrGLSLShaderBuilder_DEFINED
#define GrGLSLShaderBuilder_DEFINED
#include "include/private/SkTDArray.h"
#include "src/gpu/GrShaderVar.h"
#include "src/gpu/GrTAllocator.h"
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
#include "src/sksl/SkSLString.h"
#include <stdarg.h>
class GrGLSLColorSpaceXformHelper;
/**
base class for all shaders builders
*/
class GrGLSLShaderBuilder {
public:
GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
virtual ~GrGLSLShaderBuilder() {}
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
/** Appends a 2D texture sample with projection if necessary. The vec length and swizzle
order of the result depends on the GrProcessor::TextureSampler associated with the
SamplerHandle.
*/
void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const;
/** Version of above that appends the result to the shader code instead.*/
void appendTextureLookup(SamplerHandle,
const char* coordName,
GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
/** Does the work of appendTextureLookup and blends the result by dst, treating the texture
lookup a the src input to the blend. The dst is assumed to be half4 and the result is always
a half4. If dst is nullptr we use half4(1) as the blend dst. */
void appendTextureLookupAndBlend(const char* dst,
SkBlendMode,
SamplerHandle,
const char* coordName,
GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
/** Adds a helper function to facilitate color gamut transformation, and produces code that
returns the srcColor transformed into a new gamut (via multiplication by the xform from
colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
determines if the source is premultipled or not). */
void appendColorGamutXform(SkString* out, const char* srcColor,
GrGLSLColorSpaceXformHelper* colorXformHelper);
/** Version of above that appends the result to the shader code instead. */
void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
/**
* Adds a constant declaration to the top of the shader.
*/
void defineConstant(const char* type, const char* name, const char* value) {
this->definitions().appendf("const %s %s = %s;\n", type, name, value);
}
void defineConstant(const char* name, int value) {
this->definitions().appendf("const int %s = %i;\n", name, value);
}
void defineConstant(const char* name, float value) {
this->definitions().appendf("const float %s = %f;\n", name, value);
}
void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
this->definitions().appendf("const %s %s = ", type, name);
va_list args;
va_start(args, fmt);
this->definitions().appendVAList(fmt, args);
va_end(args);
this->definitions().append(";\n");
}
void declareGlobal(const GrShaderVar&);
// Generates a unique variable name for holding the result of a temporary expression when it's
// not reasonable to just add a new block for scoping. Does not declare anything.
SkString newTmpVarName(const char* suffix) {
int tmpIdx = fTmpVariableCounter++;
return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix);
}
/**
* Called by GrGLSLProcessors to add code to one of the shaders.
*/
void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
va_list args;
va_start(args, format);
this->code().appendVAList(format, args);
va_end(args);
}
void codeAppend(const char* str) { this->code().append(str); }
void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
va_list args;
va_start(args, format);
this->code().prependVAList(format, args);
va_end(args);
}
/**
* Appends a variable declaration to one of the shaders
*/
void declAppend(const GrShaderVar& var);
/** Emits a helper function outside of main() in the fragment shader. */
void emitFunction(GrSLType returnType,
const char* name,
int argCnt,
const GrShaderVar* args,
const char* body,
SkString* outName);
/*
* Combines the various parts of the shader to create a single finalized shader string.
*/
void finalize(uint32_t visibility);
/*
* Get parent builder for adding uniforms
*/
GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
/**
* Helper for begining and ending a block in the shader code.
*/
class ShaderBlock {
public:
ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
SkASSERT(builder);
fBuilder->codeAppend("{");
}
~ShaderBlock() {
fBuilder->codeAppend("}");
}
private:
GrGLSLShaderBuilder* fBuilder;
};
protected:
typedef GrTAllocator<GrShaderVar> VarArray;
void appendDecls(const VarArray& vars, SkString* out) const;
/**
* Features that should only be enabled internally by the builders.
*/
enum GLSLPrivateFeature {
kFragCoordConventions_GLSLPrivateFeature,
kBlendEquationAdvanced_GLSLPrivateFeature,
kBlendFuncExtended_GLSLPrivateFeature,
kFramebufferFetch_GLSLPrivateFeature,
kNoPerspectiveInterpolation_GLSLPrivateFeature,
kSampleVariables_GLSLPrivateFeature,
kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature
};
/*
* A general function which enables an extension in a shader if the feature bit is not present
*
* @return true if the feature bit was not yet present, false otherwise.
*/
bool addFeature(uint32_t featureBit, const char* extensionName);
enum InterfaceQualifier {
kIn_InterfaceQualifier,
kOut_InterfaceQualifier,
kLastInterfaceQualifier = kOut_InterfaceQualifier
};
/*
* A low level function to build default layout qualifiers.
*
* e.g. layout(param1, param2, ...) out;
*
* GLSL allows default layout qualifiers for in, out, and uniform.
*/
void addLayoutQualifier(const char* param, InterfaceQualifier);
void compileAndAppendLayoutQualifiers();
void nextStage() {
fShaderStrings.push_back();
fCodeIndex++;
}
void deleteStage() {
fShaderStrings.pop_back();
fCodeIndex--;
}
SkString& extensions() { return fShaderStrings[kExtensions]; }
SkString& definitions() { return fShaderStrings[kDefinitions]; }
SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
SkString& uniforms() { return fShaderStrings[kUniforms]; }
SkString& inputs() { return fShaderStrings[kInputs]; }
SkString& outputs() { return fShaderStrings[kOutputs]; }
SkString& functions() { return fShaderStrings[kFunctions]; }
SkString& main() { return fShaderStrings[kMain]; }
SkString& code() { return fShaderStrings[fCodeIndex]; }
virtual void onFinalize() = 0;
enum {
kExtensions,
kDefinitions,
kPrecisionQualifier,
kLayoutQualifiers,
kUniforms,
kInputs,
kOutputs,
kFunctions,
kMain,
kCode,
kPrealloc = kCode + 6, // 6 == Reasonable upper bound on number of processor stages
};
GrGLSLProgramBuilder* fProgramBuilder;
SkSL::String fCompilerString;
SkSTArray<kPrealloc, SkString> fShaderStrings;
SkString fCode;
SkString fFunctions;
SkString fExtensions;
VarArray fInputs;
VarArray fOutputs;
uint32_t fFeaturesAddedMask;
SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
int fCodeIndex;
bool fFinalized;
// Counter for generating unique scratch variable names in a shader.
int fTmpVariableCounter;
friend class GrCCCoverageProcessor; // to access code().
friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder;
friend class GrD3DPipelineStateBuilder;
friend class GrDawnProgramBuilder;
friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
friend class GrGLPathProgramBuilder; // to access fInputs.
friend class GrVkPipelineStateBuilder;
friend class GrMtlPipelineStateBuilder;
};
#endif