/* * 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 GrBackendEffectFactory_DEFINED #define GrBackendEffectFactory_DEFINED #include "GrTypes.h" #include "SkTemplates.h" #include "SkThread.h" #include "SkTypes.h" #include "SkTArray.h" class GrGLEffect; class GrGLCaps; class GrDrawEffect; /** * Used by effects to build their keys. It incorporates each per-effect key into a larger shader key. */ class GrEffectKeyBuilder { public: GrEffectKeyBuilder(SkTArray* 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(&v)); } /** Inserts count uint32_ts into the key. The returned pointer is only valid until the next add*() call. */ uint32_t* SK_WARN_UNUSED_RESULT add32n(int count) { SkASSERT(count > 0); fCount += count; return reinterpret_cast(fData->push_back_n(4 * count)); } size_t size() const { return sizeof(uint32_t) * fCount; } private: SkTArray* fData; // unowned ptr to the larger key. int fCount; // number of uint32_ts added to fData by the effect. }; /** * This class is used to pass the key that was created for a GrGLEffect back to it * when it emits code. It may allow the emit step to skip calculations that were * performed when computing the key. */ class GrEffectKey { public: GrEffectKey(const uint32_t* key, int count) : fKey(key), fCount(count) { SkASSERT(0 == reinterpret_cast(key) % sizeof(uint32_t)); } /** Gets the uint32_t values that the effect inserted into the key. */ uint32_t get32(int index) const { SkASSERT(index >=0 && index < fCount); return fKey[index]; } /** Gets the number of uint32_t values that the effect inserted into the key. */ int count32() const { return fCount; } private: const uint32_t* fKey; // unowned ptr into the larger key. int fCount; // number of uint32_ts inserted by the effect into its key. }; /** * Given a GrEffect of a particular type, creates the corresponding graphics-backend-specific * effect object. It also tracks equivalence of shaders generated via a key. The factory for an * effect is accessed via GrEffect::getFactory(). Each factory instance is assigned an ID at * construction. The ID of GrEffect::getFactory() is used as a type identifier. Thus, a GrEffect * subclass must always return the same object from getFactory() and that factory object must be * unique to the GrEffect subclass (and unique from any further derived subclasses). * * Rather than subclassing this class themselves, it is recommended that GrEffect authors use * the templated subclass GrTBackendEffectFactory by writing their getFactory() method as: * * const GrBackendEffectFactory& MyEffect::getFactory() const { * return GrTBackendEffectFactory::getInstance(); * } * * Using GrTBackendEffectFactory places a few constraints on the effect. See that class's comments. */ class GrBackendEffectFactory : SkNoncopyable { public: /** * Generates an effect's key. The key is based on the aspects of the GrEffect object's * configuration that affect GLSL code generation. Two GrEffect instances that would cause * this->createGLInstance()->emitCode() to produce different code must produce different keys. */ virtual void getGLEffectKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) const = 0; /** * Creates a GrGLEffect instance that is used both to generate code for the GrEffect in a GLSL * program and to manage updating uniforms for the program when it is used. */ virtual GrGLEffect* createGLInstance(const GrDrawEffect&) const = 0; /** * Produces a human-reable name for the effect. */ virtual const char* name() const = 0; /** * A unique value for every instance of this factory. It is automatically incorporated into the * effect's key. This allows keys generated by getGLEffectKey() to only be unique within a * GrEffect subclass and not necessarily across subclasses. */ uint32_t effectClassID() const { return fEffectClassID; } protected: GrBackendEffectFactory() : fEffectClassID(GenID()) {} virtual ~GrBackendEffectFactory() {} private: enum { kIllegalEffectClassID = 0, }; static uint32_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. uint32_t id = static_cast(sk_atomic_inc(&fCurrEffectClassID)) + 1; if (!id) { SkFAIL("This should never wrap as it should only be called once for each GrEffect " "subclass."); } return id; } const uint32_t fEffectClassID; static int32_t fCurrEffectClassID; }; #endif