/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrGLSLProgramBuilder_DEFINED
#define GrGLSLProgramBuilder_DEFINED
#include "GrCaps.h"
#include "GrGeometryProcessor.h"
#include "GrGpu.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLGeometryShaderBuilder.h"
#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLUniformHandler.h"
#include "glsl/GrGLSLVertexShaderBuilder.h"
#include "glsl/GrGLSLXferProcessor.h"
class GrShaderVar;
class GrGLSLVaryingHandler;
class GrGLSLExpr4;
class GrShaderCaps;
typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs;
class GrGLSLProgramBuilder {
public:
using UniformHandle = GrGLSLUniformHandler::UniformHandle;
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
virtual ~GrGLSLProgramBuilder() {}
virtual const GrCaps* caps() const = 0;
const GrShaderCaps* shaderCaps() const { return this->caps()->shaderCaps(); }
const GrPrimitiveProcessor& primitiveProcessor() const { return fPrimProc; }
const GrPipeline& pipeline() const { return fPipeline; }
GrProgramDesc* desc() { return fDesc; }
const GrProgramDesc::KeyHeader& header() const { return fDesc->header(); }
void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
const GrShaderVar& samplerVariable(SamplerHandle handle) const {
return this->uniformHandler()->samplerVariable(handle);
}
GrSwizzle samplerSwizzle(SamplerHandle handle) const {
return this->uniformHandler()->samplerSwizzle(handle);
}
const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const {
return this->uniformHandler()->imageStorageVariable(handle);
}
// Handles for program uniforms (other than per-effect uniforms)
struct BuiltinUniformHandles {
UniformHandle fRTAdjustmentUni;
// We use the render target height to provide a y-down frag coord when specifying
// origin_upper_left is not supported.
UniformHandle fRTHeightUni;
};
// Used to add a uniform for the RenderTarget height (used for frag position) without mangling
// the name of the uniform inside of a stage.
void addRTHeightUniform(const char* name);
// Generates a name for a variable. The generated string will be name prefixed by the prefix
// char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless
// explicitly asked not to.
void nameVariable(SkString* out, char prefix, const char* name, bool mangle = true);
virtual GrGLSLUniformHandler* uniformHandler() = 0;
virtual const GrGLSLUniformHandler* uniformHandler() const = 0;
virtual GrGLSLVaryingHandler* varyingHandler() = 0;
// Used for backend customization of the output color and secondary color variables from the
// fragment processor. Only used if the outputs are explicitly declared in the shaders
virtual void finalizeFragmentOutputColor(GrShaderVar& outputColor) {}
virtual void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {}
// number of each input/output type in a single allocation block, used by many builders
static const int kVarsPerBlock;
GrGLSLVertexBuilder fVS;
GrGLSLGeometryBuilder fGS;
GrGLSLFragmentShaderBuilder fFS;
int fStageIndex;
const GrPipeline& fPipeline;
const GrPrimitiveProcessor& fPrimProc;
GrProgramDesc* fDesc;
BuiltinUniformHandles fUniformHandles;
GrGLSLPrimitiveProcessor* fGeometryProcessor;
GrGLSLXferProcessor* fXferProcessor;
GrGLSLFragProcs fFragmentProcessors;
protected:
explicit GrGLSLProgramBuilder(const GrPipeline&,
const GrPrimitiveProcessor&,
GrProgramDesc*);
void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName);
bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage);
void cleanupFragmentProcessors();
void finalizeShaders();
private:
// reset is called by program creator between each processor's emit code. It increments the
// stage offset for variable name mangling, and also ensures verfication variables in the
// fragment shader are cleared.
void reset() {
this->addStage();
SkDEBUGCODE(fFS.resetVerification();)
}
void addStage() { fStageIndex++; }
class AutoStageAdvance {
public:
AutoStageAdvance(GrGLSLProgramBuilder* pb)
: fPB(pb) {
fPB->reset();
// Each output to the fragment processor gets its own code section
fPB->fFS.nextStage();
}
~AutoStageAdvance() {}
private:
GrGLSLProgramBuilder* fPB;
};
// Generates a possibly mangled name for a stage variable and writes it to the fragment shader.
// If GrGLSLExpr4 has a valid name then it will use that instead
void nameExpression(GrGLSLExpr4*, const char* baseName);
void emitAndInstallPrimProc(const GrPrimitiveProcessor&,
GrGLSLExpr4* outputColor,
GrGLSLExpr4* outputCoverage);
void emitAndInstallFragProcs(GrGLSLExpr4* colorInOut, GrGLSLExpr4* coverageInOut);
void emitAndInstallFragProc(const GrFragmentProcessor&,
int index,
int transformedCoordVarsIdx,
const GrGLSLExpr4& input,
GrGLSLExpr4* output);
void emitAndInstallXferProc(const GrXferProcessor&,
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn);
void emitSamplersAndImageStorages(const GrProcessor& processor,
SkTArray<SamplerHandle>* outTexSamplerHandles,
SkTArray<SamplerHandle>* outBufferSamplerHandles,
SkTArray<ImageStorageHandle>* outImageStorageHandles);
void emitSampler(GrSLType samplerType, GrPixelConfig, const char* name,
GrShaderFlags visibility, SkTArray<SamplerHandle >* outSamplerHandles);
void emitImageStorage(const GrProcessor::ImageStorageAccess&,
const char* name,
SkTArray<ImageStorageHandle>* outImageStorageHandles);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
bool checkSamplerCounts();
bool checkImageStorageCounts();
#ifdef SK_DEBUG
void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&);
void verify(const GrFragmentProcessor&);
#endif
int fNumVertexSamplers;
int fNumGeometrySamplers;
int fNumFragmentSamplers;
int fNumVertexImageStorages;
int fNumGeometryImageStorages;
int fNumFragmentImageStorages;
SkSTArray<4, GrShaderVar> fTransformedCoordVars;
};
#endif