diff options
author | tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-20 18:35:38 +0000 |
---|---|---|
committer | tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-20 18:35:38 +0000 |
commit | 07eecdca3e331eb4066c53a29305aeea6d692961 (patch) | |
tree | d511d99cc07f13525d8a87292c8d48d075b2d8ea /src/gpu | |
parent | 5a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3 (diff) |
Hooks up the GrCustomStage/GrGLProgramStageFactory/GrGLProgramStage
classes from r3726 so they can be used. Does not implement any actual
effect stages.
Has one large known bug: if custom stages are provided, GrSamplerState
comparisons will break; this should preserve correct drawing, but decrease
performance - among other things, we'll break draw batching. To fix this
we'll need a RTTI system for GrCustomState objects, and we'll need to change
the GrSamplerState comparison from a memcmp to something that also does a
deep type-sensitive compare of any GrCustomState objects present.
http://codereview.appspot.com/6074043/
git-svn-id: http://skia.googlecode.com/svn/trunk@3742 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrCustomStage.h | 34 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 96 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 17 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramStage.h | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGLShaders.cpp | 56 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGLShaders.h | 4 |
6 files changed, 161 insertions, 57 deletions
diff --git a/src/gpu/GrCustomStage.h b/src/gpu/GrCustomStage.h deleted file mode 100644 index a5b8133c7f..0000000000 --- a/src/gpu/GrCustomStage.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCustomStage_DEFINED -#define GrCustomStage_DEFINED - -class GrContext; -class GrGLProgramStageFactory; - -/** Provides custom vertex shader, fragment shader, uniform data for a - particular stage of the Ganesh shading pipeline. - TODO: may want to refcount these? */ -class GrCustomStage { - -public: - - GrCustomStage(); - virtual ~GrCustomStage(); - - /** If given an input texture that is/is not opaque, is this - stage guaranteed to produce an opaque output? */ - virtual bool isOpaque(bool inputTextureIsOpaque) const; - - virtual GrGLProgramStageFactory* getGLFactory() = 0; - -protected: - -}; - -#endif diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 16a60cee91..fb98b4d3a7 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -10,6 +10,8 @@ #include "GrGLProgram.h" #include "../GrAllocator.h" +#include "GrCustomStage.h" +#include "GrGLProgramStage.h" #include "GrGLShaderVar.h" #include "SkTrace.h" #include "SkXfermode.h" @@ -620,8 +622,17 @@ const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const { } } +// If this destructor is in the header file, we must include GrGLProgramStage +// instead of just forward-declaring it. +GrGLProgram::CachedData::~CachedData() { + for (int i = 0; i < GrDrawState::kNumStages; ++i) { + delete fCustomStage[i]; + } +} + bool GrGLProgram::genProgram(const GrGLContextInfo& gl, + GrCustomStage** customStages, GrGLProgram::CachedData* programData) const { ShaderCodeSegments segments; @@ -733,6 +744,21 @@ bool GrGLProgram::genProgram(const GrGLContextInfo& gl, } /////////////////////////////////////////////////////////////////////////// + // Convert generic effect representation to GL-specific backend so they + // can be accesseed in genStageCode() and in subsequent uses of + // programData. + for (int s = 0; s < GrDrawState::kNumStages; ++s) { + GrCustomStage* customStage = customStages[s]; + if (NULL != customStage) { + GrGLProgramStageFactory* factory = customStage->getGLFactory(); + programData->fCustomStage[s] = + factory->createGLInstance(customStage); + } else { + programData->fCustomStage[s] = NULL; + } + } + + /////////////////////////////////////////////////////////////////////////// // compute the final color // if we have color stages string them together, feeding the output color @@ -766,7 +792,8 @@ bool GrGLProgram::genProgram(const GrGLContextInfo& gl, outColor.c_str(), inCoords, &segments, - &programData->fUniLocations.fStages[s]); + &programData->fUniLocations.fStages[s], + programData->fCustomStage[s]); inColor = outColor; } } @@ -878,13 +905,14 @@ bool GrGLProgram::genProgram(const GrGLContextInfo& gl, inCoords = texCoordAttrs[tcIdx].c_str(); } - genStageCode(gl, s, - fProgramDesc.fStages[s], - inCoverage.size() ? inCoverage.c_str() : NULL, - outCoverage.c_str(), - inCoords, - &segments, - &programData->fUniLocations.fStages[s]); + this->genStageCode(gl, s, + fProgramDesc.fStages[s], + inCoverage.size() ? inCoverage.c_str() : NULL, + outCoverage.c_str(), + inCoords, + &segments, + &programData->fUniLocations.fStages[s], + programData->fCustomStage[s]); inCoverage = outCoverage; } } @@ -1348,6 +1376,11 @@ void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl, imageIncrementName.c_str())); GrAssert(kUnusedUniform != locations.fImageIncrementUni); } + + if (NULL != programData->fCustomStage[s]) { + programData->fCustomStage[s]-> + initUniforms(gl.interface(), progID); + } } } GL_CALL(UseProgram(progID)); @@ -1363,6 +1396,7 @@ void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl, programData->fTextureWidth[s] = -1; programData->fTextureHeight[s] = -1; programData->fTextureDomain[s].setEmpty(); + // Must not reset fStageOverride[] here. } programData->fViewMatrix = GrMatrix::InvalidMatrix(); programData->fColor = GrColor_ILLEGAL; @@ -1712,7 +1746,8 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, const char* fsOutColor, const char* vsInCoord, ShaderCodeSegments* segments, - StageUniLocations* locations) const { + StageUniLocations* locations, + GrGLProgramStage* customStage) const { GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages); GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == @@ -1723,8 +1758,13 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, // gradients. static const int coordDims = 2; int varyingDims; + /// Vertex Shader Stuff + if (NULL != customStage) { + customStage->setupVSUnis(segments->fVSUnis, stageNum); + } + // decide whether we need a matrix to transform texture coords // and whether the varying needs a perspective coord. const char* matName = NULL; @@ -1808,7 +1848,20 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, &imageIncrementName, varyingVSName); } + if (NULL != customStage) { + GrStringBuilder vertexShader; + customStage->emitVS(&vertexShader, varyingVSName); + segments->fVSCode.appendf("{\n"); + segments->fVSCode.append(vertexShader); + segments->fVSCode.appendf("}\n"); + } + /// Fragment Shader Stuff + + if (NULL != customStage) { + customStage->setupFSUnis(segments->fFSUnis, stageNum); + } + GrStringBuilder fsCoordName; // function used to access the shader, may be made projective GrStringBuilder texFunc("texture2D"); @@ -1959,6 +2012,31 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, swizzle, modulate.c_str()); } } + + if (NULL != customStage) { + if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | + StageDesc::kNoPerspective_OptFlagBit)) { + customStage->setSamplerMode(GrGLProgramStage::kDefault_SamplerMode); + } else if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && + StageDesc::kSingle_FetchMode == desc.fFetchMode) { + customStage->setSamplerMode(GrGLProgramStage::kProj_SamplerMode); + } else { + customStage->setSamplerMode( + GrGLProgramStage::kExplicitDivide_SamplerMode); + } + + GrStringBuilder fragmentShader; + fsCoordName = customStage->emitTextureSetup( + &fragmentShader, varyingFSName, + stageNum, coordDims, varyingDims); + customStage->emitFS(&fragmentShader, fsOutColor, fsInColor, + samplerName, fsCoordName.c_str()); + + // Enclose custom code in a block to avoid namespace conflicts + segments->fFSCode.appendf("{\n"); + segments->fFSCode.append(fragmentShader); + segments->fFSCode.appendf("}\n"); + } } diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 0d8c39a786..73bfa949a6 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -19,6 +19,7 @@ #include "SkXfermode.h" class GrBinHashKeyBuilder; +class GrGLProgramStage; struct ShaderCodeSegments; @@ -49,6 +50,7 @@ public: * but in a separate cacheable container. */ bool genProgram(const GrGLContextInfo& gl, + GrCustomStage** customStages, CachedData* programData) const; /** @@ -180,6 +182,10 @@ public: uint8_t fCoordMapping; // casts to enum CoordMapping uint8_t fKernelWidth; + /** Non-zero if user-supplied code will write the stage's + contribution to the fragment shader. */ + uint16_t fCustomStageKey; + GR_STATIC_ASSERT((InConfigFlags)(uint8_t)kInConfigBitMask == kInConfigBitMask); @@ -305,10 +311,12 @@ public: class CachedData : public ::GrNoncopyable { public: CachedData() { + for (int i = 0; i < GrDrawState::kNumStages; ++i) { + fCustomStage[i] = NULL; + } } - ~CachedData() { - } + ~CachedData(); void copyAndTakeOwnership(CachedData& other) { memcpy(this, &other, sizeof(*this)); @@ -340,6 +348,8 @@ public: bool fRadial2PosRoot[GrDrawState::kNumStages]; GrRect fTextureDomain[GrDrawState::kNumStages]; + GrGLProgramStage* fCustomStage[GrDrawState::kNumStages]; + private: enum Constants { kUniLocationPreAllocSize = 8 @@ -366,7 +376,8 @@ private: const char* fsOutColor, const char* vsInCoord, ShaderCodeSegments* segments, - StageUniLocations* locations) const; + StageUniLocations* locations, + GrGLProgramStage* override) const; void genGeometryShader(const GrGLContextInfo& gl, ShaderCodeSegments* segments) const; diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h index 83c736d0dd..a56439980c 100644 --- a/src/gpu/gl/GrGLProgramStage.h +++ b/src/gpu/gl/GrGLProgramStage.h @@ -96,8 +96,6 @@ public: void setSamplerMode(SamplerMode shaderMode) { fSamplerMode = shaderMode; } -protected: - /** Returns the *effective* coord name after any perspective divide or other transform. */ GrStringBuilder emitTextureSetup(GrStringBuilder* code, @@ -106,6 +104,8 @@ protected: int coordDims, int varyingDims); +protected: + /** Convenience function for subclasses to write texture2D() or texture2DProj(), depending on fSamplerMode. */ void emitTextureLookup(GrStringBuilder* code, @@ -130,16 +130,19 @@ public: /** Returns a short unique identifier for this subclass x its parameters. If the key differs, different shader code must be generated; if the key matches, shader code can be reused. - 0 == no custom stage. */ + 0 == no custom stage. */ virtual uint16_t stageKey(const GrCustomStage*); + /** Returns a new instance of the appropriate implementation class + for the given GrCustomStage; caller is responsible for deleting + the object. */ virtual GrGLProgramStage* createGLInstance(GrCustomStage*) = 0; protected: /** Disable default constructor - instances should be singletons with static factory functions: our test examples are all stateless, - but we suspect that future implementations may want to cache data? */ + but we suspect that future implementations may want to cache data? */ GrGLProgramStageFactory() { } }; diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp index 9627107e79..1fcfbbee2b 100644 --- a/src/gpu/gl/GrGpuGLShaders.cpp +++ b/src/gpu/gl/GrGpuGLShaders.cpp @@ -8,7 +8,9 @@ #include "../GrBinHashKey.h" +#include "GrCustomStage.h" #include "GrGLProgram.h" +#include "GrGLProgramStage.h" #include "GrGLSL.h" #include "GrGpuGLShaders.h" #include "../GrGpuVertex.h" @@ -82,13 +84,14 @@ public: } } - GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) { + GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc, + GrCustomStage** stages) { Entry newEntry; newEntry.fKey.setKeyData(desc.keyData()); Entry* entry = fHashCache.find(newEntry.fKey); if (NULL == entry) { - if (!desc.genProgram(fGL, &newEntry.fProgramData)) { + if (!desc.genProgram(fGL, stages, &newEntry.fProgramData)) { return NULL; } if (fCount < kMaxEntries) { @@ -242,6 +245,8 @@ bool GrGpuGLShaders::programUnitTest() { pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput; } + GrCustomStage* customStages[GrDrawState::kNumStages]; + for (int s = 0; s < GrDrawState::kNumStages; ++s) { // enable the stage? if (random_bool(&random)) { @@ -288,9 +293,13 @@ bool GrGpuGLShaders::programUnitTest() { stage.fInConfigFlags &= ~kMulByAlphaMask; break; } + + stage.fCustomStageKey = 0; + customStages[s] = NULL; } CachedData cachedData; - if (!program.genProgram(this->glContextInfo(), &cachedData)) { + if (!program.genProgram(this->glContextInfo(), customStages, + &cachedData)) { return false; } DeleteProgram(this->glInterface(), &cachedData); @@ -772,8 +781,10 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { return false; } - this->buildProgram(type, blendOpts, dstCoeff); - fProgramData = fProgramCache->getProgramData(fCurrentProgram); + GrCustomStage* customStages [GrDrawState::kNumStages]; + this->buildProgram(type, blendOpts, dstCoeff, customStages); + fProgramData = fProgramCache->getProgramData(fCurrentProgram, + customStages); if (NULL == fProgramData) { GrAssert(!"Failed to create program!"); return false; @@ -814,6 +825,13 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { this->flushTexelSize(s); this->flushTextureDomain(s); + + if (NULL != fProgramData->fCustomStage[s]) { + const GrSamplerState& sampler = + this->getDrawState().getSampler(s); + fProgramData->fCustomStage[s]->setData( + this->glInterface(), sampler.getCustomStage()); + } } } this->flushEdgeAAData(); @@ -962,9 +980,29 @@ void GrGpuGLShaders::setupGeometry(int* startVertex, fHWGeometryState.fArrayPtrsDirty = false; } +namespace { + +void setup_custom_stage(GrGLProgram::ProgramDesc::StageDesc* stage, + const GrSamplerState& sampler, + GrCustomStage** customStages, + GrGLProgram* program, int index) { + GrCustomStage* customStage = sampler.getCustomStage(); + if (customStage) { + GrGLProgramStageFactory* factory = customStage->getGLFactory(); + stage->fCustomStageKey = factory->stageKey(customStage); + customStages[index] = customStage; + } else { + stage->fCustomStageKey = 0; + customStages[index] = NULL; + } +} + +} + void GrGpuGLShaders::buildProgram(GrPrimitiveType type, BlendOptFlags blendOpts, - GrBlendCoeff dstCoeff) { + GrBlendCoeff dstCoeff, + GrCustomStage** customStages) { ProgramDesc& desc = fCurrentProgram.fProgramDesc; const GrDrawState& drawState = this->getDrawState(); @@ -1170,12 +1208,18 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type, } else { stage.fKernelWidth = 0; } + + setup_custom_stage(&stage, sampler, customStages, + &fCurrentProgram, s); + } else { stage.fOptFlags = 0; stage.fCoordMapping = (StageDesc::CoordMapping) 0; stage.fInConfigFlags = 0; stage.fFetchMode = (StageDesc::FetchMode) 0; stage.fKernelWidth = 0; + stage.fCustomStageKey = 0; + customStages[s] = NULL; } } diff --git a/src/gpu/gl/GrGpuGLShaders.h b/src/gpu/gl/GrGpuGLShaders.h index 39bc97471d..2ce95eb28f 100644 --- a/src/gpu/gl/GrGpuGLShaders.h +++ b/src/gpu/gl/GrGpuGLShaders.h @@ -14,6 +14,7 @@ #include "GrGpuGL.h" #include "GrGLProgram.h" +class GrCustomStage; class GrGpuGLProgram; // Programmable OpenGL or OpenGL ES 2.0 @@ -86,7 +87,8 @@ private: void buildProgram(GrPrimitiveType typeBlend, BlendOptFlags blendOpts, - GrBlendCoeff dstCoeff); + GrBlendCoeff dstCoeff, + GrCustomStage** customStages); ProgramCache* fProgramCache; CachedData* fProgramData; |