1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef GrProgramDesc_DEFINED
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define GrProgramDesc_DEFINED
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrColor.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTypesPriv.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpts.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTArray.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "glsl/GrGLSLFragmentShaderBuilder.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrShaderCaps;
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrPipeline;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrPrimitiveProcessor;
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/** This class describes a program to generate. It also serves as a program cache key */
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrProgramDesc {
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Creates an uninitialized key that must be populated by GrGpu::buildProgramDesc()
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrProgramDesc() {}
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * Builds a program descriptor. Before the descriptor can be used, the client must call finalize
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * on the returned GrProgramDesc.
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * @param GrPrimitiveProcessor The geometry
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * @param hasPointSize Controls whether the shader will output a point size.
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * @param GrPipeline  The optimized drawstate.  The descriptor will represent a program
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *                        which this optstate can use to draw with.  The optstate contains
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *                        general draw information, as well as the specific color, geometry,
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *                        and coverage stages which will be used to generate the GL Program for
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *                        this optstate.
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * @param GrShaderCaps   Capabilities of the shading language.
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    * @param GrProgramDesc  The built and finalized descriptor
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    **/
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static bool Build(GrProgramDesc*,
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      const GrPrimitiveProcessor&,
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      bool hasPointSize,
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      const GrPipeline&,
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      const GrShaderCaps&);
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Returns this as a uint32_t array to be used as a key in the program cache.
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint32_t* asKey() const {
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return reinterpret_cast<const uint32_t*>(fKey.begin());
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // keys the size of either key can be used with memcmp() since the lengths themselves begin the
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // keys and thus the memcmp will exit early if the keys are of different lengths.
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint32_t keyLength() const { return *this->atOffset<uint32_t, kLengthOffset>(); }
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Gets the a checksum of the key. Can be used as a hash value for a fast lookup in a cache.
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); }
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrProgramDesc& operator= (const GrProgramDesc& other) {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t keyLength = other.keyLength();
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fKey.reset(SkToInt(keyLength));
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(fKey.begin(), other.fKey.begin(), keyLength);
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *this;
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool operator== (const GrProgramDesc& that) const {
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(SkIsAlign4(this->keyLength()));
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int l = this->keyLength() >> 2;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t* aKey = this->asKey();
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t* bKey = that.asKey();
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < l; ++i) {
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (aKey[i] != bKey[i]) {
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool operator!= (const GrProgramDesc& other) const {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return !(*this == other);
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setSurfaceOriginKey(int key) {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        KeyHeader* header = this->atOffset<KeyHeader, kHeaderOffset>();
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        header->fSurfaceOriginKey = key;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static bool Less(const GrProgramDesc& a, const GrProgramDesc& b) {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(SkIsAlign4(a.keyLength()));
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int l = a.keyLength() >> 2;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t* aKey = a.asKey();
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t* bKey = b.asKey();
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < l; ++i) {
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (aKey[i] != bKey[i]) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return aKey[i] < bKey[i] ? true : false;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct KeyHeader {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Set to uniquely identify the sample pattern, or 0 if the shader doesn't use sample
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // locations.
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fSamplePatternKey;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Set to uniquely idenitify any swizzling of the shader's output color(s).
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fOutputSwizzle;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fColorFragmentProcessorCnt : 4;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fCoverageFragmentProcessorCnt : 4;
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info.
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fSurfaceOriginKey : 2;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fSnapVerticesToPixelCenters : 1;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fHasPointSize : 1;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t                     fPad : 4;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GR_STATIC_ASSERT(sizeof(KeyHeader) == 4);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This should really only be used internally, base classes should return their own headers
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const KeyHeader& header() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void finalize() {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int keyLength = fKey.count();
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0 == (keyLength % 4));
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *(this->atOffset<uint32_t, GrProgramDesc::kLengthOffset>()) = SkToU32(keyLength);
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* checksum = this->atOffset<uint32_t, GrProgramDesc::kChecksumOffset>();
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *checksum = 0;  // We'll hash through these bytes, so make sure they're initialized.
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *checksum = SkOpts::hash(fKey.begin(), keyLength);
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    template<typename T, size_t OFFSET> T* atOffset() {
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    template<typename T, size_t OFFSET> const T* atOffset() const {
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The key, stored in fKey, is composed of four parts:
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 1. uint32_t for total key length.
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 2. uint32_t for a checksum.
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 3. Header struct defined above.
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 4. A Backend specific payload which includes the per-processor keys.
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    enum KeyOffsets {
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Part 1.
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kLengthOffset = 0,
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Part 2.
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kChecksumOffset = kLengthOffset + sizeof(uint32_t),
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Part 3.
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kHeaderOffset = kChecksumOffset + sizeof(uint32_t),
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kHeaderSize = SkAlign4(sizeof(KeyHeader)),
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Part 4.
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // This is the offset into the backenend specific part of the key, which includes
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // per-processor keys.
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kProcessorKeysOffset = kHeaderOffset + kHeaderSize,
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    enum {
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kMaxPreallocProcessors = 8,
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kIntsPerProcessor      = 4,    // This is an overestimate of the average effect key size.
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kPreAllocSize = kHeaderOffset + kHeaderSize +
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        kMaxPreallocProcessors * sizeof(uint32_t) * kIntsPerProcessor,
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkSTArray<kPreAllocSize, uint8_t, true>& key() { return fKey; }
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkSTArray<kPreAllocSize, uint8_t, true>& key() const { return fKey; }
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkSTArray<kPreAllocSize, uint8_t, true> fKey;
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
174