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