aboutsummaryrefslogtreecommitdiffhomepage
path: root/include/gpu/GrBackendEffectFactory.h
blob: 936d632a7e6248496b159d950db906c61a7d70f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * 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 GrEffect;

/**
 * Used by effects to build their keys. It incorporates 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));
    }

    /** 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<uint32_t*>(fData->push_back_n(4 * count));
    }

    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.
};

/**
 * 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<intptr_t>(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<MyEffect>::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 GrEffect&, 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 GrEffect&) 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<uint32_t>(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