Move some program building utils from GL to GLSL

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1535603006

Review URL: https://codereview.chromium.org/1535603006
This commit is contained in:
egdaniel 2016-01-13 12:19:30 -08:00 committed by Commit bot
parent b76afedf11
commit fa8963252e
10 changed files with 362 additions and 367 deletions

View File

@ -107,6 +107,35 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) {
GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType);
GR_STATIC_ASSERT(9 == kGrSLTypeCount);
}
/** Returns the size in bytes for floating point GrSLTypes. For non floating point type returns 0 */
static inline size_t GrSLTypeSize(GrSLType type) {
SkASSERT(GrSLTypeIsFloatType(type));
static const size_t kSizes[] = {
0, // kVoid_GrSLType
sizeof(float), // kFloat_GrSLType
2 * sizeof(float), // kVec2f_GrSLType
3 * sizeof(float), // kVec3f_GrSLType
4 * sizeof(float), // kVec4f_GrSLType
9 * sizeof(float), // kMat33f_GrSLType
16 * sizeof(float), // kMat44f_GrSLType
0, // kSampler2D_GrSLType
0 // kSamplerExternal_GrSLType
};
return kSizes[type];
GR_STATIC_ASSERT(0 == kVoid_GrSLType);
GR_STATIC_ASSERT(1 == kFloat_GrSLType);
GR_STATIC_ASSERT(2 == kVec2f_GrSLType);
GR_STATIC_ASSERT(3 == kVec3f_GrSLType);
GR_STATIC_ASSERT(4 == kVec4f_GrSLType);
GR_STATIC_ASSERT(5 == kMat33f_GrSLType);
GR_STATIC_ASSERT(6 == kMat44f_GrSLType);
GR_STATIC_ASSERT(7 == kSampler2D_GrSLType);
GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType);
GR_STATIC_ASSERT(9 == kGrSLTypeCount);
}
//////////////////////////////////////////////////////////////////////////////
/**

View File

@ -31,15 +31,15 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu,
GrGLuint programID,
const UniformInfoArray& uniforms,
const VaryingInfoArray& pathProcVaryings,
GrGLInstalledGeoProc* geometryProcessor,
GrGLInstalledXferProc* xferProcessor,
GrGLInstalledFragProcs* fragmentProcessors,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors,
SkTArray<UniformHandle>* passSamplerUniforms)
: fBuiltinUniformHandles(builtinUniforms)
, fProgramID(programID)
, fGeometryProcessor(geometryProcessor)
, fXferProcessor(xferProcessor)
, fFragmentProcessors(SkRef(fragmentProcessors))
, fFragmentProcessors(fragmentProcessors)
, fDesc(desc)
, fGpu(gpu)
, fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) {
@ -55,6 +55,9 @@ GrGLProgram::~GrGLProgram() {
if (fProgramID) {
GL_CALL(DeleteProgram(fProgramID));
}
for (int i = 0; i < fFragmentProcessors.count(); ++i) {
delete fFragmentProcessors[i];
}
}
void GrGLProgram::abandon() {
@ -63,12 +66,9 @@ void GrGLProgram::abandon() {
///////////////////////////////////////////////////////////////////////////////
template <class Proc>
static void append_texture_bindings(const Proc* ip,
const GrProcessor& processor,
static void append_texture_bindings(const GrProcessor& processor,
SkTArray<const GrTextureAccess*>* textureBindings) {
if (int numTextures = processor.numTextures()) {
SkASSERT(textureBindings->count() == ip->fSamplersIdx);
const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures);
int i = 0;
do {
@ -84,37 +84,32 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc,
// we set the textures, and uniforms for installed processors in a generic way, but subclasses
// of GLProgram determine how to set coord transforms
fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc);
append_texture_bindings(fGeometryProcessor.get(), primProc, textureBindings);
fGeometryProcessor->setData(fProgramDataManager, primProc);
append_texture_bindings(primProc, textureBindings);
this->setFragmentData(primProc, pipeline, textureBindings);
const GrXferProcessor& xp = pipeline.getXferProcessor();
fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
append_texture_bindings(fXferProcessor.get(), xp, textureBindings);
fXferProcessor->setData(fProgramDataManager, xp);
append_texture_bindings(xp, textureBindings);
}
void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline,
SkTArray<const GrTextureAccess*>* textureBindings) {
int numProcessors = fFragmentProcessors->fProcs.count();
int numProcessors = fFragmentProcessors.count();
for (int i = 0; i < numProcessors; ++i) {
const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i);
fFragmentProcessors->fProcs[i]->fGLProc->setData(fProgramDataManager, processor);
this->setTransformData(primProc,
processor,
i,
fFragmentProcessors->fProcs[i]);
append_texture_bindings(fFragmentProcessors->fProcs[i], processor, textureBindings);
fFragmentProcessors[i]->setData(fProgramDataManager, processor);
this->setTransformData(primProc, processor, i);
append_texture_bindings(processor, textureBindings);
}
}
void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc,
const GrFragmentProcessor& processor,
int index,
GrGLInstalledFragProc* ip) {
GrGLSLPrimitiveProcessor* gp = fGeometryProcessor.get()->fGLProc.get();
gp->setTransformData(primProc, fProgramDataManager, index,
processor.coordTransforms());
int index) {
fGeometryProcessor->setTransformData(primProc, fProgramDataManager, index,
processor.coordTransforms());
}
void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,

View File

@ -108,9 +108,9 @@ protected:
GrGLuint programID,
const UniformInfoArray&,
const VaryingInfoArray&, // used for NVPR only currently
GrGLInstalledGeoProc* geometryProcessor,
GrGLInstalledXferProc* xferProcessor,
GrGLInstalledFragProcs* fragmentProcessors,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors,
SkTArray<UniformHandle>* passSamplerUniforms);
// A templated helper to loop over effects, set the transforms(via subclass) and bind textures
@ -118,8 +118,7 @@ protected:
SkTArray<const GrTextureAccess*>* textureBindings);
void setTransformData(const GrPrimitiveProcessor&,
const GrFragmentProcessor&,
int index,
GrGLInstalledFragProc*);
int index);
// Helper for setData() that sets the view matrix and loads the render target height uniform
void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&);
@ -130,9 +129,9 @@ protected:
GrGLuint fProgramID;
// the installed effects
SkAutoTDelete<GrGLInstalledGeoProc> fGeometryProcessor;
SkAutoTDelete<GrGLInstalledXferProc> fXferProcessor;
SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
SkAutoTDelete<GrGLSLPrimitiveProcessor> fGeometryProcessor;
SkAutoTDelete<GrGLSLXferProcessor> fXferProcessor;
GrGLSLFragProcs fFragmentProcessors;
GrProgramDesc fDesc;
GrGLGpu* fGpu;

View File

@ -42,7 +42,10 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp
GrGLSLExpr4 inputColor;
GrGLSLExpr4 inputCoverage;
if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) {
if (!pb->emitAndInstallProcs(&inputColor,
&inputCoverage,
gpu->glCaps().maxFragmentTextureUnits())) {
pb->cleanupFragmentProcessors();
return nullptr;
}
@ -53,243 +56,18 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp
GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
: INHERITED(args)
, fGeometryProcessor(nullptr)
, fXferProcessor(nullptr)
, fGpu(gpu)
, fSamplerUniforms(4)
, fVaryingHandler(this)
, fUniformHandler(this) {
}
const GrCaps* GrGLProgramBuilder::caps() const {
return fGpu->caps();
}
const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const {
return this->fGpu->ctxInfo().caps()->glslCaps();
}
bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
// First we loop over all of the installed processors and collect coord transforms. These will
// be sent to the GrGLSLPrimitiveProcessor in its emitCode function
const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
int totalTextures = primProc.numTextures();
const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
if (!primProc.hasTransformedLocalCoords()) {
SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
processor.gatherCoordTransforms(&procCoords);
}
totalTextures += processor.numTextures();
if (totalTextures >= maxTextureUnits) {
GrCapsDebugf(fGpu->caps(), "Program would use too many texture units\n");
return false;
}
}
this->emitAndInstallProc(primProc, inputColor, inputCoverage);
fFragmentProcessors.reset(new GrGLInstalledFragProcs);
int numProcs = this->pipeline().numFragmentProcessors();
this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
inputCoverage);
this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
this->pipeline().ignoresCoverage());
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
return true;
}
void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
int numProcs,
GrGLSLExpr4* inOut) {
for (int i = procOffset; i < numProcs; ++i) {
GrGLSLExpr4 output;
const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
this->emitAndInstallProc(fp, i, *inOut, &output);
*inOut = output;
}
}
void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
// create var to hold stage result. If we already have a valid output name, just use that
// otherwise create a new mangled one. This name is only valid if we are reordering stages
// and have to tell stage exactly where to put its output.
SkString outName;
if (output->isValid()) {
outName = output->c_str();
} else {
this->nameVariable(&outName, '\0', baseName);
}
fFS.codeAppendf("vec4 %s;", outName.c_str());
*output = outName;
}
// TODO Processors cannot output zeros because an empty string is all 1s
// the fix is to allow effects to take the GrGLSLExpr4 directly
void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
int index,
const GrGLSLExpr4& input,
GrGLSLExpr4* output) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
this->nameExpression(output, "output");
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
fFS.codeAppend(openBrace.c_str());
this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str());
fFS.codeAppend("}");
}
void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
GrGLSLExpr4* outputColor,
GrGLSLExpr4* outputCoverage) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
this->nameExpression(outputColor, "outputColor");
this->nameExpression(outputCoverage, "outputCoverage");
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
fFS.codeAppend(openBrace.c_str());
fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str());
fFS.codeAppend("}");
}
void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
int index,
const char* outColor,
const char* inColor) {
GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc;
ifp->fGLProc.reset(fp.createGLSLInstance());
SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
this->emitSamplers(fp, &samplers, ifp);
GrGLSLFragmentProcessor::EmitArgs args(&fFS,
&fUniformHandler,
this->glslCaps(),
fp,
outColor,
inColor,
fOutCoords[index],
samplers);
ifp->fGLProc->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(fp);
fFragmentProcessors->fProcs.push_back(ifp);
}
void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
const char* outColor,
const char* outCoverage) {
SkASSERT(!fGeometryProcessor);
fGeometryProcessor = new GrGLInstalledGeoProc;
fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glslCaps()));
SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures());
this->emitSamplers(gp, &samplers, fGeometryProcessor);
GrGLSLGeometryProcessor::EmitArgs args(&fVS,
&fFS,
&fVaryingHandler,
&fUniformHandler,
this->glslCaps(),
gp,
outColor,
outCoverage,
samplers,
fCoordTransforms,
&fOutCoords);
fGeometryProcessor->fGLProc->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(gp);
}
void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
SkASSERT(!fXferProcessor);
fXferProcessor = new GrGLInstalledXferProc;
fXferProcessor->fGLProc.reset(xp.createGLSLInstance());
// Enable dual source secondary output if we have one
if (xp.hasSecondaryOutput()) {
fFS.enableSecondaryOutput();
}
if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
fFS.enableCustomOutput();
}
SkString openBrace;
openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
fFS.codeAppend(openBrace.c_str());
SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
this->emitSamplers(xp, &samplers, fXferProcessor);
GrGLSLXferProcessor::EmitArgs args(&fFS,
&fUniformHandler,
this->glslCaps(),
xp, colorIn.c_str(),
ignoresCoverage ? nullptr : coverageIn.c_str(),
fFS.getPrimaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
samplers);
fXferProcessor->fGLProc->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(xp);
fFS.codeAppend("}");
}
void GrGLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
// Swizzle the fragment shader outputs if necessary.
GrSwizzle swizzle;
swizzle.setFromKey(this->desc().header().fOutputSwizzle);
if (swizzle != GrSwizzle::RGBA()) {
fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
fFS.getPrimaryColorOutputName(),
swizzle.c_str());
if (hasSecondaryOutput) {
fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
swizzle.c_str());
}
}
}
void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
}
void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
}
void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
return fGpu->ctxInfo().caps()->glslCaps();
}
static GrSLType get_sampler_type(const GrTextureAccess& access) {
@ -302,11 +80,8 @@ static GrSLType get_sampler_type(const GrTextureAccess& access) {
}
}
template <class Proc>
void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
GrGLInstalledProc<Proc>* ip) {
SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();)
GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
int numTextures = processor.numTextures();
UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
SkString name;
@ -356,6 +131,7 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
GrGLuint programID;
GL_CALL_RET(programID, CreateProgram());
if (0 == programID) {
this->cleanupFragmentProcessors();
return nullptr;
}
@ -474,7 +250,8 @@ void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
GL_CALL(DeleteProgram(programID));
cleanupShaders(shaderIDs);
this->cleanupShaders(shaderIDs);
this->cleanupFragmentProcessors();
}
void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
for (int i = 0; i < shaderIDs.count(); ++i) {
@ -491,15 +268,7 @@ GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
fVaryingHandler.fPathProcVaryingInfos,
fGeometryProcessor,
fXferProcessor,
fFragmentProcessors.get(),
fFragmentProcessors,
&fSamplerUniforms);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
int numProcs = fProcs.count();
for (int i = 0; i < numProcs; ++i) {
delete fProcs[i];
}
}

View File

@ -12,42 +12,14 @@
#include "gl/GrGLProgramDataManager.h"
#include "gl/GrGLUniformHandler.h"
#include "gl/GrGLVaryingHandler.h"
#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLTextureSampler.h"
#include "glsl/GrGLSLXferProcessor.h"
class GrFragmentProcessor;
class GrGLContextInfo;
class GrGLSLShaderBuilder;
class GrGLSLCaps;
/**
* The below struct represent processors installed in programs.
*/
template <class Proc>
struct GrGLInstalledProc {
SkDEBUGCODE(int fSamplersIdx;)
SkAutoTDelete<Proc> fGLProc;
};
typedef GrGLInstalledProc<GrGLSLPrimitiveProcessor> GrGLInstalledGeoProc;
typedef GrGLInstalledProc<GrGLSLXferProcessor> GrGLInstalledXferProc;
typedef GrGLInstalledProc<GrGLSLFragmentProcessor> GrGLInstalledFragProc;
struct GrGLInstalledFragProcs : public SkRefCnt {
virtual ~GrGLInstalledFragProcs();
SkSTArray<8, GrGLInstalledFragProc*, true> fProcs;
};
/*
* Please note - no diamond problems because of virtual inheritance. Also, both base classes
* are pure virtual with no data members. This is the base class for program building.
* Subclasses are nearly identical but each has their own way of emitting transforms. State for
* each of the elements of the shader pipeline, ie vertex, fragment, geometry, etc, lives in those
* respective builders
*/
class GrGLProgramBuilder : public GrGLSLProgramBuilder {
public:
/** Generates a shader program.
@ -59,6 +31,7 @@ public:
*/
static GrGLProgram* CreateProgram(const DrawArgs&, GrGLGpu*);
const GrCaps* caps() const override;
const GrGLSLCaps* glslCaps() const override;
GrGLGpu* gpu() const { return fGpu; }
@ -66,41 +39,8 @@ public:
private:
GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
// 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);
bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage);
void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut);
void emitAndInstallProc(const GrFragmentProcessor&,
int index,
const GrGLSLExpr4& input,
GrGLSLExpr4* output);
void emitAndInstallProc(const GrPrimitiveProcessor&,
GrGLSLExpr4* outputColor,
GrGLSLExpr4* outputCoverage);
// these emit functions help to keep the createAndEmitProcessors template general
void emitAndInstallProc(const GrFragmentProcessor&,
int index,
const char* outColor,
const char* inColor);
void emitAndInstallProc(const GrPrimitiveProcessor&,
const char* outColor,
const char* outCoverage);
void emitAndInstallXferProc(const GrXferProcessor&,
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&);
void verify(const GrFragmentProcessor&);
template <class Proc>
void emitSamplers(const GrProcessor&,
GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
GrGLInstalledProc<Proc>*);
GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override;
bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
GrGLuint programId,
@ -120,35 +60,8 @@ private:
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
// 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();
fFS.reset();
}
void addStage() { fStageIndex++; }
class AutoStageAdvance {
public:
AutoStageAdvance(GrGLProgramBuilder* pb)
: fPB(pb) {
fPB->reset();
// Each output to the fragment processor gets its own code section
fPB->fFS.nextStage();
}
~AutoStageAdvance() {}
private:
GrGLProgramBuilder* fPB;
};
GrGLInstalledGeoProc* fGeometryProcessor;
GrGLInstalledXferProc* fXferProcessor;
SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
GrGLGpu* fGpu;
GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
SkTArray<UniformHandle> fSamplerUniforms;

View File

@ -158,6 +158,7 @@ private:
GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization.
friend class GrVkCaps;
typedef GrShaderCaps INHERITED;
};

View File

@ -194,6 +194,7 @@ private:
bool fHasReadDstColor;
bool fHasReadFragmentPosition;
friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder;
typedef GrGLSLXPFragmentBuilder INHERITED;

View File

@ -7,6 +7,11 @@
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrPipeline.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLXferProcessor.h"
const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
@ -14,7 +19,203 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
, fGS(this)
, fFS(this, args.fDesc->header().fFragPosKey)
, fStageIndex(-1)
, fArgs(args) {
, fArgs(args)
, fGeometryProcessor(nullptr)
, fXferProcessor(nullptr) {
}
bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
GrGLSLExpr4* inputCoverage,
int maxTextures) {
// First we loop over all of the installed processors and collect coord transforms. These will
// be sent to the GrGLSLPrimitiveProcessor in its emitCode function
const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
int totalTextures = primProc.numTextures();
for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
if (!primProc.hasTransformedLocalCoords()) {
SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
processor.gatherCoordTransforms(&procCoords);
}
totalTextures += processor.numTextures();
if (totalTextures >= maxTextures) {
GrCapsDebugf(this->caps(), "Program would use too many texture units\n");
return false;
}
}
this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
int numProcs = this->pipeline().numFragmentProcessors();
this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
inputCoverage);
this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
this->pipeline().ignoresCoverage());
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
return true;
}
void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
GrGLSLExpr4* outputColor,
GrGLSLExpr4* outputCoverage) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
this->nameExpression(outputColor, "outputColor");
this->nameExpression(outputCoverage, "outputCoverage");
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
fFS.codeAppend(openBrace.c_str());
fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
SkASSERT(!fGeometryProcessor);
fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures());
this->emitSamplers(proc, &samplers);
GrGLSLGeometryProcessor::EmitArgs args(&fVS,
&fFS,
this->varyingHandler(),
this->uniformHandler(),
this->glslCaps(),
proc,
outputColor->c_str(),
outputCoverage->c_str(),
samplers,
fCoordTransforms,
&fOutCoords);
fGeometryProcessor->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(proc);
fFS.codeAppend("}");
}
void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset,
int numProcs,
GrGLSLExpr4* inOut) {
for (int i = procOffset; i < numProcs; ++i) {
GrGLSLExpr4 output;
const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
this->emitAndInstallFragProc(fp, i, *inOut, &output);
*inOut = output;
}
}
// TODO Processors cannot output zeros because an empty string is all 1s
// the fix is to allow effects to take the GrGLSLExpr4 directly
void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
int index,
const GrGLSLExpr4& input,
GrGLSLExpr4* output) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
this->nameExpression(output, "output");
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
fFS.codeAppend(openBrace.c_str());
GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
this->emitSamplers(fp, &samplers);
GrGLSLFragmentProcessor::EmitArgs args(&fFS,
this->uniformHandler(),
this->glslCaps(),
fp,
output->c_str(),
input.isOnes() ? nullptr : input.c_str(),
fOutCoords[index],
samplers);
fragProc->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(fp);
fFragmentProcessors.push_back(fragProc);
fFS.codeAppend("}");
}
void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage) {
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
SkASSERT(!fXferProcessor);
fXferProcessor = xp.createGLSLInstance();
// Enable dual source secondary output if we have one
if (xp.hasSecondaryOutput()) {
fFS.enableSecondaryOutput();
}
if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
fFS.enableCustomOutput();
}
SkString openBrace;
openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
fFS.codeAppend(openBrace.c_str());
SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
this->emitSamplers(xp, &samplers);
GrGLSLXferProcessor::EmitArgs args(&fFS,
this->uniformHandler(),
this->glslCaps(),
xp, colorIn.c_str(),
ignoresCoverage ? nullptr : coverageIn.c_str(),
fFS.getPrimaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
samplers);
fXferProcessor->emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
verify(xp);
fFS.codeAppend("}");
}
void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
// Swizzle the fragment shader outputs if necessary.
GrSwizzle swizzle;
swizzle.setFromKey(this->desc().header().fOutputSwizzle);
if (swizzle != GrSwizzle::RGBA()) {
fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
fFS.getPrimaryColorOutputName(),
swizzle.c_str());
if (hasSecondaryOutput) {
fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
swizzle.c_str());
}
}
}
void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
}
void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
}
void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
}
void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
@ -32,6 +233,20 @@ void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char*
}
}
void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
// create var to hold stage result. If we already have a valid output name, just use that
// otherwise create a new mangled one. This name is only valid if we are reordering stages
// and have to tell stage exactly where to put its output.
SkString outName;
if (output->isValid()) {
outName = output->c_str();
} else {
this->nameVariable(&outName, '\0', baseName);
}
fFS.codeAppendf("vec4 %s;", outName.c_str());
*output = outName;
}
void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
SkString* out) const {
this->uniformHandler()->appendUniformDecls(visibility, out);
@ -58,3 +273,9 @@ void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** out
name, false, 0, outName);
}
void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
for (int i = 0; i < fFragmentProcessors.count(); ++i) {
delete fFragmentProcessors[i];
}
}

View File

@ -12,14 +12,19 @@
#include "GrGpu.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLGeometryShaderBuilder.h"
#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLUniformHandler.h"
#include "glsl/GrGLSLTextureSampler.h"
#include "glsl/GrGLSLVertexShaderBuilder.h"
#include "glsl/GrGLSLXferProcessor.h"
class GrGLSLCaps;
class GrGLSLShaderVar;
class GrGLSLVaryingHandler;
typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs;
class GrGLSLProgramBuilder {
public:
typedef GrGpu::DrawArgs DrawArgs;
@ -28,6 +33,7 @@ public:
virtual ~GrGLSLProgramBuilder() {}
virtual const GrCaps* caps() const = 0;
virtual const GrGLSLCaps* glslCaps() const = 0;
const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; }
@ -76,8 +82,67 @@ public:
BuiltinUniformHandles fUniformHandles;
GrGLSLPrimitiveProcessor* fGeometryProcessor;
GrGLSLXferProcessor* fXferProcessor;
GrGLSLFragProcs fFragmentProcessors;
protected:
explicit GrGLSLProgramBuilder(const DrawArgs& args);
bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage, int maxTextures);
void cleanupFragmentProcessors();
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();
fFS.reset();
}
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(int procOffset, int numProcs, GrGLSLExpr4* inOut);
void emitAndInstallFragProc(const GrFragmentProcessor&,
int index,
const GrGLSLExpr4& input,
GrGLSLExpr4* output);
void emitAndInstallXferProc(const GrXferProcessor&,
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&);
void verify(const GrFragmentProcessor&);
virtual void emitSamplers(const GrProcessor& processor,
GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0;
GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
};
#endif

View File

@ -191,7 +191,9 @@ protected:
int fCodeIndex;
bool fFinalized;
friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder;
friend class GrGLPathProgramBuilder; // to access fInputs.
friend class GrVkProgramBuilder;
};
#endif