#include "SkTemplates.h"
#include "SkThread.h"
#include "SkTypes.h"
+#include "SkTArray.h"
/** Given a GrEffect of a particular type, creates the corresponding graphics-backend-specific
effect object. Also tracks equivalence of shaders generated via a key. Each factory instance
class GrGLCaps;
class GrDrawEffect;
+/**
+ * Used by effects to build their keys. It incorpates each per-effect key into a larger shader key.
+ */
+class GrEffectKeyBuilder {
+public:
+ GrEffectKeyBuilder(SkTArray<unsigned char, true>* data) : fData(data), fCount(0) {
+ SkASSERT(0 == fData->count() % sizeof(uint32_t));
+ }
+
+ void add32(uint32_t v) {
+ ++fCount;
+ fData->push_back_n(4, reinterpret_cast<uint8_t*>(&v));
+ }
+
+ size_t size() const { return sizeof(uint32_t) * fCount; }
+
+private:
+ SkTArray<uint8_t, true>* fData; // unowned ptr to the larger key.
+ int fCount; // number of uint32_ts added to fData by the effect.
+};
+
class GrBackendEffectFactory : SkNoncopyable {
public:
typedef uint32_t EffectKey;
- enum {
- kNoEffectKey = 0,
- kEffectKeyBits = 10,
- /**
- * The framework automatically includes coord transforms and texture accesses in their
- * effect's EffectKey, so effects don't need to account for them in GenKey().
- */
- kTextureKeyBits = 4,
- kTransformKeyBits = 6,
- kAttribKeyBits = 6,
- kClassIDBits = 6
- };
- virtual EffectKey glEffectKey(const GrDrawEffect&, const GrGLCaps&) const = 0;
+ virtual bool getGLEffectKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) const = 0;
virtual GrGLEffect* createGLInstance(const GrDrawEffect&) const = 0;
bool operator ==(const GrBackendEffectFactory& b) const {
virtual const char* name() const = 0;
- static EffectKey GetTransformKey(EffectKey key) {
- return key >> (kEffectKeyBits + kTextureKeyBits) & ((1U << kTransformKeyBits) - 1);
- }
-
protected:
enum {
kIllegalEffectClassID = 0,
}
virtual ~GrBackendEffectFactory() {}
- static EffectKey GenID() {
- SkDEBUGCODE(static const int32_t kClassIDBits = 8 * sizeof(EffectKey) -
- kTextureKeyBits - kEffectKeyBits - kAttribKeyBits);
+ static int32_t GenID() {
// fCurrEffectClassID has been initialized to kIllegalEffectClassID. The
// atomic inc returns the old value not the incremented value. So we add
// 1 to the returned value.
int32_t id = sk_atomic_inc(&fCurrEffectClassID) + 1;
- SkASSERT(id < (1 << kClassIDBits));
- return static_cast<EffectKey>(id);
+ return id;
}
- EffectKey fEffectClassID;
+ int32_t fEffectClassID;
private:
static int32_t fCurrEffectClassID;
*/
virtual const char* name() const SK_OVERRIDE { return EffectClass::Name(); }
- /** Returns a value that identifies the GLSL shader code generated by
- a GrEffect. This enables caching of generated shaders. Part of the
- id identifies the GrEffect subclass. The remainder is based
- on the aspects of the GrEffect object's configuration that affect
- GLSL code generation. */
- virtual EffectKey glEffectKey(const GrDrawEffect& drawEffect,
- const GrGLCaps& caps) const SK_OVERRIDE {
+ /** Generates an effect's key. This enables caching of generated shaders. Part of the
+ id identifies the GrEffect subclass. The remainder is based on the aspects of the
+ GrEffect object's configuration that affect GLSL code generation. If this fails
+ then program generation should be aborted. Failure occurs if the effect uses more
+ transforms, attributes, or textures than the key has space for. */
+ virtual bool getGLEffectKey(const GrDrawEffect& drawEffect,
+ const GrGLCaps& caps,
+ GrEffectKeyBuilder* b) const SK_OVERRIDE {
SkASSERT(kIllegalEffectClassID != fEffectClassID);
EffectKey effectKey = GLEffect::GenKey(drawEffect, caps);
EffectKey textureKey = GrGLProgramEffects::GenTextureKey(drawEffect, caps);
EffectKey transformKey = GrGLProgramEffects::GenTransformKey(drawEffect);
EffectKey attribKey = GrGLProgramEffects::GenAttribKey(drawEffect);
-#ifdef SK_DEBUG
- static const EffectKey kIllegalEffectKeyMask = (uint16_t) (~((1U << kEffectKeyBits) - 1));
- SkASSERT(!(kIllegalEffectKeyMask & effectKey));
-
- static const EffectKey kIllegalTextureKeyMask = (uint16_t) (~((1U << kTextureKeyBits) - 1));
- SkASSERT(!(kIllegalTextureKeyMask & textureKey));
-
- static const EffectKey kIllegalTransformKeyMask = (uint16_t) (~((1U << kTransformKeyBits) - 1));
- SkASSERT(!(kIllegalTransformKeyMask & transformKey));
-
- static const EffectKey kIllegalAttribKeyMask = (uint16_t) (~((1U << kAttribKeyBits) - 1));
- SkASSERT(!(kIllegalAttribKeyMask & textureKey));
+ static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16);
+ if ((textureKey | transformKey | attribKey | fEffectClassID) & kMetaKeyInvalidMask) {
+ return false;
+ }
- static const EffectKey kIllegalClassIDMask = (uint16_t) (~((1U << kClassIDBits) - 1));
- SkASSERT(!(kIllegalClassIDMask & fEffectClassID));
-#endif
- return (fEffectClassID << (kEffectKeyBits+kTextureKeyBits+kTransformKeyBits+kAttribKeyBits)) |
- (attribKey << (kEffectKeyBits+kTextureKeyBits+kTransformKeyBits)) |
- (transformKey << (kEffectKeyBits+kTextureKeyBits)) |
- (textureKey << kEffectKeyBits) |
- (effectKey);
+ // effectKey must be first because it is what will be returned by
+ // GrGLProgramDesc::EffectKeyProvider and passed to the GrGLEffect as its key.
+ b->add32(effectKey);
+ b->add32(textureKey << 16 | transformKey);
+ b->add32(fEffectClassID << 16 | attribKey);
+ return true;
}
/** Returns a new instance of the appropriate *GL* implementation class
#include "GrEffectUnitTest.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
/**
* GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
#include "GrCoordTransform.h"
#include "GrEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrTBackendEffectFactory.h"
#include "GrTextureAccess.h"
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrTBackendEffectFactory.h"
#endif
#include "GrTexture.h"
#include "GrEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "effects/GrSimpleTextureEffect.h"
#include "GrTBackendEffectFactory.h"
#include "SkGrPixelRef.h"
#include "GrEffectUnitTest.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
namespace {
#include "GrEffect.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
class ColorMatrixEffect : public GrEffect {
public:
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrTBackendEffectFactory.h"
#endif
#if SK_SUPPORT_GPU
#include "effects/GrSingleTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrEffect.h"
#include "GrTBackendEffectFactory.h"
#if SK_SUPPORT_GPU
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrContext.h"
#include "GrTBackendEffectFactory.h"
#endif
#if SK_SUPPORT_GPU
#include "effects/GrSingleTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "GrTBackendEffectFactory.h"
#if SK_SUPPORT_GPU
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "effects/GrSingleTextureEffect.h"
#include "GrTBackendEffectFactory.h"
#include "GrTexture.h"
#include "GrTexture.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "effects/Gr1DKernelEffect.h"
#endif
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrTBackendEffectFactory.h"
#include "SkGr.h"
#endif
#include "GrEffect.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
class GLColorTableEffect;
#include "effects/GrTextureStripAtlas.h"
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
#if SK_SUPPORT_GPU
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
/////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
class GrGLRadialGradient : public GrGLGradientEffect {
#if SK_SUPPORT_GPU
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
class GrGLSweepGradient : public GrGLGradientEffect {
#if SK_SUPPORT_GPU
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
// For brevity
typedef GrGLUniformManager::UniformHandle UniformHandle;
#if SK_SUPPORT_GPU
#include "GrTBackendEffectFactory.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkGr.h"
// For brevity
#include "SkTraceEvent.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLVertexEffect.h"
#include "GrAARectRenderer.h"
#include "GrGpu.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLVertexEffect.h"
#include "GrTBackendEffectFactory.h"
#include "SkColorPriv.h"
#include "GrEffect.h"
#include "gl/GrGLEffect.h"
#include "gl/GrGLSL.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLVertexEffect.h"
#include "GrTBackendEffectFactory.h"
#include "GrBezierEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLVertexEffect.h"
#include "GrTBackendEffectFactory.h"
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "GrBicubicEffect.h"
+#include "gl/GrGLShaderBuilder.h"
+
#define DS(x) SkDoubleToScalar(x)
const SkScalar GrBicubicEffect::gMitchellCoefficients[16] = {
#include "GrTBackendEffectFactory.h"
#include "GrSimpleTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkMatrix.h"
class GrGLConfigConversionEffect : public GrGLEffect {
#include "GrConvexPolyEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "GrTBackendEffectFactory.h"
#include "GrConvolutionEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "GrTBackendEffectFactory.h"
#include "GrCustomCoordsTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "gl/GrGLVertexEffect.h"
#include "effects/GrVertexEffect.h"
#include "gl/GrGLEffect.h"
#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "GrDistanceFieldTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "gl/GrGLVertexEffect.h"
#include "GrDitherEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "GrTBackendEffectFactory.h"
#include "GrOvalEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "GrTBackendEffectFactory.h"
#include "GrRRectEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "GrConvexPolyEffect.h"
#include "GrOvalEffect.h"
#include "GrSimpleTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "GrTBackendEffectFactory.h"
#include "GrSimpleTextureEffect.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "SkFloatingPoint.h"
#include "GrCoordTransform.h"
#include "GrEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
#include "GrTBackendEffectFactory.h"
namespace {
#include "GrBackendEffectFactory.h"
#include "GrGLProgramEffects.h"
-#include "GrGLShaderBuilder.h"
#include "GrGLShaderVar.h"
#include "GrGLSL.h"
+class GrGLShaderBuilder;
+
/** @file
This file contains specializations for OpenGL of the shader stages declared in
include/gpu/GrEffect.h. Objects of type GrGLEffect are responsible for emitting the
typedef GrGLProgramEffects::TextureSampler TextureSampler;
typedef GrGLProgramEffects::TextureSamplerArray TextureSamplerArray;
- enum {
- kNoEffectKey = GrBackendEffectFactory::kNoEffectKey,
- // the number of bits in EffectKey available to GenKey
- kEffectKeyBits = GrBackendEffectFactory::kEffectKeyBits,
- };
-
GrGLEffect(const GrBackendEffectFactory& factory)
: fFactory(factory)
, fIsVertexEffect(false) {
#include "SkChecksum.h"
-namespace {
-inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage,
- const GrGLCaps& caps,
- bool useExplicitLocalCoords,
- bool* setTrueIfReadsDst,
- bool* setTrueIfReadsPos,
- bool* setTrueIfHasVertexCode) {
- const GrEffect* effect = stage.getEffect();
- const GrBackendEffectFactory& factory = effect->getFactory();
+static inline bool get_key_and_update_stats(const GrEffectStage& stage,
+ const GrGLCaps& caps,
+ bool useExplicitLocalCoords,
+ GrEffectKeyBuilder* b,
+ bool* setTrueIfReadsDst,
+ bool* setTrueIfReadsPos,
+ bool* setTrueIfHasVertexCode) {
+ const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
- if (effect->willReadDstColor()) {
+ if (stage.getEffect()->willReadDstColor()) {
*setTrueIfReadsDst = true;
}
- if (effect->willReadFragmentPosition()) {
+ if (stage.getEffect()->willReadFragmentPosition()) {
*setTrueIfReadsPos = true;
}
- if (effect->hasVertexCode()) {
+ if (stage.getEffect()->hasVertexCode()) {
*setTrueIfHasVertexCode = true;
}
- return factory.glEffectKey(drawEffect, caps);
+ return factory.getGLEffectKey(drawEffect, caps, b);
}
-}
-void GrGLProgramDesc::Build(const GrDrawState& drawState,
+
+bool GrGLProgramDesc::Build(const GrDrawState& drawState,
GrGpu::DrawType drawType,
GrDrawState::BlendOptFlags blendOpts,
GrBlendCoeff srcCoeff,
(!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
(!inputColorIsUsed);
- int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
- (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));
-
- size_t newKeyLength = KeyLength(numEffects);
- bool allocChanged;
- desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
- if (allocChanged || !desc->fInitialized) {
- // make sure any padding in the header is zero if we we haven't used this allocation before.
- memset(desc->header(), 0, kHeaderSize);
- }
- // write the key length
- *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);
-
- KeyHeader* header = desc->header();
- EffectKey* effectKeys = desc->effectKeys();
-
- int currEffectKey = 0;
bool readsDst = false;
bool readFragPosition = false;
// We use vertexshader-less shader programs only when drawing paths.
bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
GrGpu::kDrawPaths_DrawType == drawType);
+ int numStages = 0;
+ if (!skipColor) {
+ numStages += drawState.numColorStages() - firstEffectiveColorStage;
+ }
+ if (!skipCoverage) {
+ numStages += drawState.numCoverageStages() - firstEffectiveCoverageStage;
+ }
+ GR_STATIC_ASSERT(0 == kEffectKeyLengthsOffset % sizeof(uint32_t));
+ // Make room for everything up to and including the array of offsets to effect keys.
+ desc->fKey.reset();
+ desc->fKey.push_back_n(kEffectKeyLengthsOffset + sizeof(uint32_t) * numStages);
+ size_t offset = desc->fKey.count();
+ int offsetIndex = 0;
+
+ bool effectKeySuccess = true;
if (!skipColor) {
for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
- effectKeys[currEffectKey++] =
- get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
- requiresLocalCoordAttrib, &readsDst, &readFragPosition,
- &hasVertexCode);
+ uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
+ kEffectKeyLengthsOffset +
+ offsetIndex * sizeof(uint32_t));
+ *offsetLocation = offset;
+ ++offsetIndex;
+
+ GrEffectKeyBuilder b(&desc->fKey);
+ effectKeySuccess |= get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
+ requiresLocalCoordAttrib, &b, &readsDst,
+ &readFragPosition, &hasVertexCode);
+ offset += b.size();
}
}
if (!skipCoverage) {
for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
- effectKeys[currEffectKey++] =
- get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
- requiresLocalCoordAttrib, &readsDst, &readFragPosition,
- &hasVertexCode);
+ uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(desc->fKey.begin() +
+ kEffectKeyLengthsOffset +
+ offsetIndex * sizeof(uint32_t));
+ *offsetLocation = offset;
+ ++offsetIndex;
+ GrEffectKeyBuilder b(&desc->fKey);
+ effectKeySuccess |= get_key_and_update_stats(drawState.getCoverageStage(s),
+ gpu->glCaps(), requiresLocalCoordAttrib,
+ &b, &readsDst, &readFragPosition,
+ &hasVertexCode);
+ offset += b.size();
}
}
+ if (!effectKeySuccess) {
+ desc->fKey.reset();
+ return false;
+ }
+
+ KeyHeader* header = desc->header();
+ // make sure any padding in the header is zeroed.
+ memset(desc->header(), 0, kHeaderSize);
+
+ // Because header is a pointer into the dynamic array, we can't push any new data into the key
+ // below here.
header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
header->fColorEffectCnt = colorStages->count();
header->fCoverageEffectCnt = coverageStages->count();
- *desc->checksum() = 0;
- *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
- newKeyLength);
- desc->fInitialized = true;
+ desc->finalize();
+ return true;
+}
+
+void GrGLProgramDesc::finalize() {
+ int keyLength = fKey.count();
+ SkASSERT(0 == (keyLength % 4));
+ *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);
+
+ uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
+ *checksum = 0;
+ *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
}
GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
- fInitialized = other.fInitialized;
- if (fInitialized) {
- size_t keyLength = other.keyLength();
- fKey.reset(keyLength);
- memcpy(fKey.get(), other.fKey.get(), keyLength);
- }
+ size_t keyLength = other.keyLength();
+ fKey.reset(keyLength);
+ memcpy(fKey.begin(), other.fKey.begin(), keyLength);
return *this;
}
#include "GrGLEffect.h"
#include "GrDrawState.h"
-#include "GrGLShaderBuilder.h"
#include "GrGpu.h"
class GrGpuGL;
to be API-neutral then so could this class. */
class GrGLProgramDesc {
public:
- GrGLProgramDesc() : fInitialized(false) {}
+ GrGLProgramDesc() {}
GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; }
// Returns this as a uint32_t array to be used as a key in the program cache.
const uint32_t* asKey() const {
- SkASSERT(fInitialized);
- return reinterpret_cast<const uint32_t*>(fKey.get());
+ return reinterpret_cast<const uint32_t*>(fKey.begin());
}
// Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two
uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); }
// For unit testing.
- void setRandom(SkRandom*,
+ bool setRandom(SkRandom*,
const GrGpuGL* gpu,
const GrRenderTarget* dummyDstRenderTarget,
const GrTexture* dummyDstCopyTexture,
* not contain all stages from the draw state and coverage stages from the drawState may
* be treated as color stages in the output.
*/
- static void Build(const GrDrawState&,
+ static bool Build(const GrDrawState&,
GrGpu::DrawType drawType,
GrDrawState::BlendOptFlags,
GrBlendCoeff srcCoeff,
GrGLProgramDesc* outDesc);
int numColorEffects() const {
- SkASSERT(fInitialized);
return this->getHeader().fColorEffectCnt;
}
int numCoverageEffects() const {
- SkASSERT(fInitialized);
return this->getHeader().fCoverageEffectCnt;
}
GrGLProgramDesc& operator= (const GrGLProgramDesc& other);
bool operator== (const GrGLProgramDesc& other) const {
- SkASSERT(fInitialized && other.fInitialized);
// The length is masked as a hint to the compiler that the address will be 4 byte aligned.
return 0 == memcmp(this->asKey(), other.asKey(), this->keyLength() & ~0x3);
}
}
struct KeyHeader {
- GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there
+ uint8_t fDstReadKey; // set by GrGLShaderBuilder if there
// are effects that must read the dst.
// Otherwise, 0.
- GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are
+ uint8_t fFragPosKey; // set by GrGLShaderBuilder if there are
// effects that read the fragment position.
// Otherwise, 0.
-
ColorInput fColorInput : 8;
ColorInput fCoverageInput : 8;
CoverageOutput fCoverageOutput : 8;
int8_t fCoverageEffectCnt;
};
- // The key is 1 uint32_t for the length, followed another for the checksum, the header, and then
- // the effect keys. Everything is fixed length except the effect key array.
+ // The key, stored in fKey, is composed of five parts:
+ // 1. uint32_t for total key length.
+ // 2. uint32_t for a checksum.
+ // 3. Header struct defined above.
+ // 4. uint32_t offsets to beginning of every effects' key (see 5).
+ // 5. per-effect keys. Each effect's key is a variable length array of uint32_t.
enum {
kLengthOffset = 0,
kChecksumOffset = kLengthOffset + sizeof(uint32_t),
kHeaderOffset = kChecksumOffset + sizeof(uint32_t),
kHeaderSize = SkAlign4(sizeof(KeyHeader)),
- kEffectKeyOffset = kHeaderOffset + kHeaderSize,
+ kEffectKeyLengthsOffset = kHeaderOffset + kHeaderSize,
};
template<typename T, size_t OFFSET> T* atOffset() {
- return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
+ return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
}
template<typename T, size_t OFFSET> const T* atOffset() const {
- return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
+ return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
}
- typedef GrGLEffect::EffectKey EffectKey;
+ typedef GrBackendEffectFactory::EffectKey EffectKey;
- uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); }
KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); }
- EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
+
+ void finalize();
const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); }
- const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
- static size_t KeyLength(int effectCnt) {
- GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3));
- return kEffectKeyOffset + effectCnt * sizeof(EffectKey);
- }
+ /** Used to provide effects' keys to their emitCode() function. */
+ class EffectKeyProvider {
+ public:
+ enum EffectType {
+ kColor_EffectType,
+ kCoverage_EffectType,
+ };
+
+ EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) {
+ // Coverage effect key offsets begin immediately after those of the color effects.
+ fBaseIndex = kColor_EffectType == type ? 0 : desc->numColorEffects();
+ }
+
+ EffectKey get(int index) const {
+ const uint32_t* offsets = reinterpret_cast<const uint32_t*>(fDesc->fKey.begin() +
+ kEffectKeyLengthsOffset);
+ uint32_t offset = offsets[fBaseIndex + index];
+ return *reinterpret_cast<const EffectKey*>(fDesc->fKey.begin() + offset);
+ }
+ private:
+ const GrGLProgramDesc* fDesc;
+ int fBaseIndex;
+ };
enum {
- kMaxPreallocEffects = 16,
- kPreAllocSize = kEffectKeyOffset + kMaxPreallocEffects * sizeof(EffectKey),
+ kMaxPreallocEffects = 8,
+ kIntsPerEffect = 4, // This is an overestimate of the average effect key size.
+ kPreAllocSize = kEffectKeyLengthsOffset +
+ kMaxPreallocEffects * sizeof(uint32_t) * kIntsPerEffect,
};
- SkAutoSMalloc<kPreAllocSize> fKey;
- bool fInitialized;
+ SkSTArray<kPreAllocSize, uint8_t, true> fKey;
- // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all
- // code generation to GrGLShaderBuilder (and maybe add getters rather than friending).
+ // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Split out
+ // part of GrGLShaderBuilder that is used by effects so that this header doesn't need to be
+ // visible to GrGLEffects. Then make public accessors as necessary and remove friends.
friend class GrGLProgram;
friend class GrGLShaderBuilder;
friend class GrGLFullShaderBuilder;
SkSTArray<4, TextureSampler> samplers(effect->numTextures());
this->emitAttributes(builder, stage);
- this->emitTransforms(builder, effect, key, &coords);
+ this->emitTransforms(builder, drawEffect, &coords);
this->emitSamplers(builder, effect, &samplers);
GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
}
void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder,
- const GrEffect* effect,
- EffectKey effectKey,
+ const GrDrawEffect& drawEffect,
TransformedCoordsArray* outCoords) {
SkTArray<Transform, true>& transforms = fTransforms.push_back();
- EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
- int numTransforms = effect->numTransforms();
+ EffectKey totalKey = GenTransformKey(drawEffect);
+ int numTransforms = drawEffect.effect()->numTransforms();
transforms.push_back_n(numTransforms);
for (int t = 0; t < numTransforms; t++) {
GrSLType varyingType = kVoid_GrSLType;
SkSTArray<4, TextureSampler> samplers(effect->numTextures());
SkASSERT(0 == stage.getVertexAttribIndexCount());
- this->setupPathTexGen(builder, effect, key, &coords);
+ this->setupPathTexGen(builder, drawEffect, &coords);
this->emitSamplers(builder, effect, &samplers);
GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
}
void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder,
- const GrEffect* effect,
- EffectKey effectKey,
+ const GrDrawEffect& drawEffect,
TransformedCoordsArray* outCoords) {
- int numTransforms = effect->numTransforms();
- EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
+ int numTransforms = drawEffect.effect()->numTransforms();
+ EffectKey totalKey = GenTransformKey(drawEffect);
int texCoordIndex = builder->addTexCoordSets(numTransforms);
SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex));
SkString name;
* TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function.
*/
void emitTransforms(GrGLFullShaderBuilder*,
- const GrEffect*,
- EffectKey,
+ const GrDrawEffect&,
TransformedCoordsArray*);
/**
* effect's emitCode() function.
*/
void setupPathTexGen(GrGLFragmentOnlyShaderBuilder*,
- const GrEffect*,
- EffectKey,
+ const GrDrawEffect&,
TransformedCoordsArray*);
/**
///////////////////////////////////////////////////////////////////////////
// emit the per-effect code for both color and coverage effects
+ GrGLProgramDesc::EffectKeyProvider colorKeyProvider(
+ &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType);
fOutput.fColorEffects.reset(this->createAndEmitEffects(colorStages,
- this->desc().getEffectKeys(),
this->desc().numColorEffects(),
+ colorKeyProvider,
&inputColor));
+ GrGLProgramDesc::EffectKeyProvider coverageKeyProvider(
+ &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType);
fOutput.fCoverageEffects.reset(this->createAndEmitEffects(coverageStages,
- this->desc().getEffectKeys() + this->desc().numColorEffects(),
- this->desc().numCoverageEffects(),
- &inputCoverage));
+ this->desc().numCoverageEffects(),
+ coverageKeyProvider,
+ &inputCoverage));
this->emitCodeAfterEffects();
void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider,
GrGLSLExpr4* fsInOutColor) {
bool effectEmitted = false;
programEffectsBuilder->emitEffect(stage,
- effectKeys[e],
+ keyProvider.get(e),
outColor.c_str(),
inColor.isOnes() ? NULL : inColor.c_str(),
fCodeStage.stageIndex());
GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects(
const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider,
GrGLSLExpr4* inOutFSColor) {
GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
effectStages,
- effectKeys,
effectCnt,
+ keyProvider,
inOutFSColor);
return programEffectsBuilder.finish();
}
GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects(
const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider,
GrGLSLExpr4* inOutFSColor) {
GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this,
effectCnt);
this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder,
effectStages,
- effectKeys,
effectCnt,
+ keyProvider,
inOutFSColor);
return pathTexGenEffectsBuilder.finish();
}
#include "GrColor.h"
#include "GrEffect.h"
#include "SkTypes.h"
+#include "gl/GrGLProgramDesc.h"
#include "gl/GrGLProgramEffects.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLUniformManager.h"
// Helper for emitEffects().
void createAndEmitEffects(GrGLProgramEffectsBuilder*,
const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider&,
GrGLSLExpr4* inOutFSColor);
// Generates a name for a variable. The generated string will be name prefixed by the prefix
/**
* Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
- * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key
- * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and
- * is updated to be the output color of the last stage.
- * The handles to texture samplers for effectStage[i] are added to
+ * deleting it when finished. effectStages contains the effects to add. The effect key provider
+ * is used to communicate the key each effect created in its GenKey function. inOutFSColor
+ * specifies the input color to the first stage and is updated to be the output color of the
+ * last stage. The handles to texture samplers for effectStage[i] are added to
* effectSamplerHandles[i].
*/
virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider&,
GrGLSLExpr4* inOutFSColor) = 0;
/**
virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider&,
GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
virtual void emitCodeAfterEffects() SK_OVERRIDE;
virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
- const EffectKey effectKeys[],
int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider&,
GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
virtual void emitCodeAfterEffects() SK_OVERRIDE {}
SkSTArray<8, const GrEffectStage*, true> colorStages;
SkSTArray<8, const GrEffectStage*, true> coverageStages;
GrGLProgramDesc desc;
- GrGLProgramDesc::Build(this->getDrawState(),
+ if (!GrGLProgramDesc::Build(this->getDrawState(),
type,
blendOpts,
srcCoeff,
dstCopy,
&colorStages,
&coverageStages,
- &desc);
+ &desc)) {
+ SkDEBUGFAIL("Failed to generate GL program descriptor");
+ return false;
+ }
fCurrentProgram.reset(fProgramCache->getProgram(desc,
colorStages.begin(),
#include "SkRandom.h"
#include "Test.h"
-void GrGLProgramDesc::setRandom(SkRandom* random,
+bool GrGLProgramDesc::setRandom(SkRandom* random,
const GrGpuGL* gpu,
const GrRenderTarget* dstRenderTarget,
const GrTexture* dstCopyTexture,
int numColorStages,
int numCoverageStages,
int currAttribIndex) {
- int numEffects = numColorStages + numCoverageStages;
- size_t keyLength = KeyLength(numEffects);
- fKey.reset(keyLength);
- *this->atOffset<uint32_t, kLengthOffset>() = static_cast<uint32_t>(keyLength);
- memset(this->header(), 0, kHeaderSize);
+ bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
+
+ int numStages = numColorStages + numCoverageStages;
+ fKey.reset();
+
+ GR_STATIC_ASSERT(0 == kEffectKeyLengthsOffset % sizeof(uint32_t));
+
+ // Make room for everything up to and including the array of offsets to effect keys.
+ fKey.push_back_n(kEffectKeyLengthsOffset + sizeof(uint32_t) * numStages);
+
+ size_t offset = fKey.count();
+ int offsetIndex = 0;
+
+ bool dstRead = false;
+ bool fragPos = false;
+ bool vertexCode = false;
+ for (int s = 0; s < numStages; ++s) {
+ uint32_t* offsetLocation = reinterpret_cast<uint32_t*>(fKey.begin() +
+ kEffectKeyLengthsOffset +
+ offsetIndex * sizeof(uint32_t));
+ *offsetLocation = offset;
+ ++offsetIndex;
+
+ const GrBackendEffectFactory& factory = stages[s]->getEffect()->getFactory();
+ GrDrawEffect drawEffect(*stages[s], useLocalCoords);
+ GrEffectKeyBuilder b(&fKey);
+ if (!factory.getGLEffectKey(drawEffect, gpu->glCaps(), &b)) {
+ fKey.reset();
+ return false;
+ }
+ if (stages[s]->getEffect()->willReadDstColor()) {
+ dstRead = true;
+ }
+ if (stages[s]->getEffect()->willReadFragmentPosition()) {
+ fragPos = true;
+ }
+ if (stages[s]->getEffect()->hasVertexCode()) {
+ vertexCode = true;
+ }
+
+ offset += b.size();
+ }
KeyHeader* header = this->header();
+ memset(header, 0, kHeaderSize);
header->fEmitsPointSize = random->nextBool();
header->fPositionAttributeIndex = 0;
random->nextULessThan(kColorInputCnt));
} while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
kAttribute_ColorInput == header->fColorInput);
+
header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
currAttribIndex++ :
-1;
header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
#endif
- bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
header->fColorEffectCnt = numColorStages;
header->fCoverageEffectCnt = numCoverageStages;
- bool dstRead = false;
- bool fragPos = false;
- bool vertexCode = false;
- int numStages = numColorStages + numCoverageStages;
- for (int s = 0; s < numStages; ++s) {
- const GrBackendEffectFactory& factory = stages[s]->getEffect()->getFactory();
- GrDrawEffect drawEffect(*stages[s], useLocalCoords);
- this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
- if (stages[s]->getEffect()->willReadDstColor()) {
- dstRead = true;
- }
- if (stages[s]->getEffect()->willReadFragmentPosition()) {
- fragPos = true;
- }
- if (stages[s]->getEffect()->hasVertexCode()) {
- vertexCode = true;
- }
- }
-
if (dstRead) {
- header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
+ header->fDstReadKey = SkToU8(GrGLShaderBuilder::KeyForDstRead(dstCopyTexture,
+ gpu->glCaps()));
} else {
header->fDstReadKey = 0;
}
if (fragPos) {
- header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
- gpu->glCaps());
+ header->fFragPosKey = SkToU8(GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
+ gpu->glCaps()));
} else {
header->fFragPosKey = 0;
}
header->fCoverageOutput = coverageOutput;
- *this->checksum() = 0;
- *this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength);
- fInitialized = true;
+ this->finalize();
+ return true;
}
bool GrGpuGL::programUnitTest(int maxStages) {
++s;
}
const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
- pdesc.setRandom(&random,
- this,
- dummyTextures[0]->asRenderTarget(),
- dstTexture,
- stages.get(),
- numColorStages,
- numCoverageStages,
- currAttribIndex);
+ if (!pdesc.setRandom(&random,
+ this,
+ dummyTextures[0]->asRenderTarget(),
+ dstTexture,
+ stages.get(),
+ numColorStages,
+ numCoverageStages,
+ currAttribIndex)) {
+ return false;
+ }
SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
pdesc,