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:
parent
b76afedf11
commit
fa8963252e
@ -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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -158,6 +158,7 @@ private:
|
||||
GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
|
||||
|
||||
friend class GrGLCaps; // For initialization.
|
||||
friend class GrVkCaps;
|
||||
|
||||
typedef GrShaderCaps INHERITED;
|
||||
};
|
||||
|
@ -194,6 +194,7 @@ private:
|
||||
bool fHasReadDstColor;
|
||||
bool fHasReadFragmentPosition;
|
||||
|
||||
friend class GrGLSLProgramBuilder;
|
||||
friend class GrGLProgramBuilder;
|
||||
|
||||
typedef GrGLSLXPFragmentBuilder INHERITED;
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user