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() GrProgramDesc()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. asKey()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. keyLength()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. getChecksum()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 setSurfaceOriginKey(int key)84 void setSurfaceOriginKey(int key) { 85 KeyHeader* header = this->atOffset<KeyHeader, kHeaderOffset>(); 86 header->fSurfaceOriginKey = key; 87 } 88 Less(const GrProgramDesc & a,const GrProgramDesc & b)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 identify the sample pattern, or 0 if the shader doesn't use sample 104 // locations. 105 uint8_t fSamplePatternKey; 106 // Set to uniquely idenitify any swizzling of the shader's output color(s). 107 uint8_t fOutputSwizzle; 108 uint8_t fColorFragmentProcessorCnt : 4; 109 uint8_t fCoverageFragmentProcessorCnt : 4; 110 // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info. 111 uint8_t fSurfaceOriginKey : 2; 112 uint8_t fSnapVerticesToPixelCenters : 1; 113 uint8_t fHasPointSize : 1; 114 uint8_t fPad : 4; 115 }; 116 GR_STATIC_ASSERT(sizeof(KeyHeader) == 4); 117 118 // This should really only be used internally, base classes should return their own headers header()119 const KeyHeader& header() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } 120 finalize()121 void finalize() { 122 int keyLength = fKey.count(); 123 SkASSERT(0 == (keyLength % 4)); 124 *(this->atOffset<uint32_t, GrProgramDesc::kLengthOffset>()) = SkToU32(keyLength); 125 126 uint32_t* checksum = this->atOffset<uint32_t, GrProgramDesc::kChecksumOffset>(); 127 *checksum = 0; // We'll hash through these bytes, so make sure they're initialized. 128 *checksum = SkOpts::hash(fKey.begin(), keyLength); 129 } 130 131 protected: atOffset()132 template<typename T, size_t OFFSET> T* atOffset() { 133 return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); 134 } 135 atOffset()136 template<typename T, size_t OFFSET> const T* atOffset() const { 137 return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); 138 } 139 140 // The key, stored in fKey, is composed of four parts: 141 // 1. uint32_t for total key length. 142 // 2. uint32_t for a checksum. 143 // 3. Header struct defined above. 144 // 4. A Backend specific payload which includes the per-processor keys. 145 enum KeyOffsets { 146 // Part 1. 147 kLengthOffset = 0, 148 // Part 2. 149 kChecksumOffset = kLengthOffset + sizeof(uint32_t), 150 // Part 3. 151 kHeaderOffset = kChecksumOffset + sizeof(uint32_t), 152 kHeaderSize = SkAlign4(sizeof(KeyHeader)), 153 // Part 4. 154 // This is the offset into the backenend specific part of the key, which includes 155 // per-processor keys. 156 kProcessorKeysOffset = kHeaderOffset + kHeaderSize, 157 }; 158 159 enum { 160 kMaxPreallocProcessors = 8, 161 kIntsPerProcessor = 4, // This is an overestimate of the average effect key size. 162 kPreAllocSize = kHeaderOffset + kHeaderSize + 163 kMaxPreallocProcessors * sizeof(uint32_t) * kIntsPerProcessor, 164 }; 165 key()166 SkSTArray<kPreAllocSize, uint8_t, true>& key() { return fKey; } key()167 const SkSTArray<kPreAllocSize, uint8_t, true>& key() const { return fKey; } 168 169 private: 170 SkSTArray<kPreAllocSize, uint8_t, true> fKey; 171 }; 172 173 #endif 174