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 "include/core/SkString.h" 12 #include "include/private/GrTypesPriv.h" 13 #include "include/private/SkTArray.h" 14 #include "include/private/SkTo.h" 15 16 #include <limits.h> 17 18 class GrCaps; 19 class GrProgramInfo; 20 class GrRenderTarget; 21 class GrShaderCaps; 22 23 class GrProcessorKeyBuilder { 24 public: GrProcessorKeyBuilder(SkTArray<uint32_t,true> * data)25 GrProcessorKeyBuilder(SkTArray<uint32_t, true>* data) : fData(data) {} 26 ~GrProcessorKeyBuilder()27 virtual ~GrProcessorKeyBuilder() { 28 // Ensure that flush was called before we went out of scope 29 SkASSERT(fBitsUsed == 0); 30 } 31 addBits(uint32_t numBits,uint32_t val,const char * label)32 virtual void addBits(uint32_t numBits, uint32_t val, const char* label) { 33 SkASSERT(numBits > 0 && numBits <= 32); 34 SkASSERT(numBits == 32 || (val < (1u << numBits))); 35 36 fCurValue |= (val << fBitsUsed); 37 fBitsUsed += numBits; 38 39 if (fBitsUsed >= 32) { 40 // Overflow, start a new working value 41 fData->push_back(fCurValue); 42 uint32_t excess = fBitsUsed - 32; 43 fCurValue = excess ? (val >> (numBits - excess)) : 0; 44 fBitsUsed = excess; 45 } 46 47 SkASSERT(fCurValue < (1u << fBitsUsed)); 48 } 49 addBytes(uint32_t numBytes,const void * data,const char * label)50 void addBytes(uint32_t numBytes, const void* data, const char* label) { 51 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data); 52 for (; numBytes --> 0; bytes++) { 53 this->addBits(8, *bytes, label); 54 } 55 } 56 addBool(bool b,const char * label)57 void addBool(bool b, const char* label) { 58 this->addBits(1, b, label); 59 } 60 61 void add32(uint32_t v, const char* label = "unknown") { 62 this->addBits(32, v, label); 63 } 64 appendComment(const char * comment)65 virtual void appendComment(const char* comment) {} 66 67 // Introduces a word-boundary in the key. Must be called before using the key with any cache, 68 // but can also be called to create a break between generic data and backend-specific data. flush()69 void flush() { 70 if (fBitsUsed) { 71 fData->push_back(fCurValue); 72 fCurValue = 0; 73 fBitsUsed = 0; 74 } 75 } 76 77 private: 78 SkTArray<uint32_t, true>* fData; 79 uint32_t fCurValue = 0; 80 uint32_t fBitsUsed = 0; // ... in current value 81 }; 82 83 class GrProcessorStringKeyBuilder : public GrProcessorKeyBuilder { 84 public: GrProcessorStringKeyBuilder(SkTArray<uint32_t,true> * data)85 GrProcessorStringKeyBuilder(SkTArray<uint32_t, true>* data) : INHERITED(data) {} 86 addBits(uint32_t numBits,uint32_t val,const char * label)87 void addBits(uint32_t numBits, uint32_t val, const char* label) override { 88 INHERITED::addBits(numBits, val, label); 89 fDescription.appendf("%s: %u\n", label, val); 90 } 91 appendComment(const char * comment)92 void appendComment(const char* comment) override { 93 fDescription.appendf("%s\n", comment); 94 } 95 description()96 SkString description() const { return fDescription; } 97 98 private: 99 using INHERITED = GrProcessorKeyBuilder; 100 SkString fDescription; 101 }; 102 103 /** This class is used to generate a generic program cache key. The Dawn, Metal and Vulkan 104 * backends derive backend-specific versions which add additional information. 105 */ 106 class GrProgramDesc { 107 public: 108 GrProgramDesc(const GrProgramDesc& other) = default; 109 GrProgramDesc& operator=(const GrProgramDesc &other) = default; 110 isValid()111 bool isValid() const { return !fKey.empty(); } reset()112 void reset() { *this = GrProgramDesc{}; } 113 114 // Returns this as a uint32_t array to be used as a key in the program cache. asKey()115 const uint32_t* asKey() const { 116 return fKey.data(); 117 } 118 119 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. keyLength()120 uint32_t keyLength() const { 121 return fKey.size() * sizeof(uint32_t); 122 } 123 124 bool operator== (const GrProgramDesc& that) const { 125 return this->fKey == that.fKey; 126 } 127 128 bool operator!= (const GrProgramDesc& other) const { 129 return !(*this == other); 130 } 131 initialKeyLength()132 uint32_t initialKeyLength() const { return fInitialKeyLength; } 133 134 // TODO(skia:11372): Incorporate this into caps interface (part of makeDesc, or a parallel 135 // function), so other backends can include their information in the description. 136 static SkString Describe(const GrProgramInfo&, const GrCaps&); 137 138 protected: 139 friend class GrDawnCaps; 140 friend class GrD3DCaps; 141 friend class GrGLCaps; 142 friend class GrMockCaps; 143 friend class GrMtlCaps; 144 friend class GrVkCaps; 145 146 friend class GrGLGpu; // for ProgramCache to access BuildFromData 147 friend class GrMtlResourceProvider; // for PipelineStateCache to access BuildFromData 148 149 // Creates an uninitialized key that must be populated by Build GrProgramDesc()150 GrProgramDesc() {} 151 152 /** 153 * Builds a program descriptor. 154 * 155 * @param desc The built descriptor 156 * @param programInfo Program information need to build the key 157 * @param caps the caps 158 **/ 159 static void Build(GrProgramDesc*, const GrProgramInfo&, const GrCaps&); 160 161 // This is strictly an OpenGL call since the other backends have additional data in their keys. BuildFromData(GrProgramDesc * desc,const void * keyData,size_t keyLength)162 static bool BuildFromData(GrProgramDesc* desc, const void* keyData, size_t keyLength) { 163 if (!SkTFitsIn<int>(keyLength) || !SkIsAlign4(keyLength)) { 164 return false; 165 } 166 desc->fKey.reset(keyLength / 4); 167 memcpy(desc->fKey.begin(), keyData, keyLength); 168 return true; 169 } 170 171 enum { 172 kHeaderSize = 1, // "header" in ::Build 173 kMaxPreallocProcessors = 8, 174 kIntsPerProcessor = 4, // This is an overestimate of the average effect key size. 175 kPreAllocSize = kHeaderSize + 176 kMaxPreallocProcessors * kIntsPerProcessor, 177 }; 178 179 using KeyType = SkSTArray<kPreAllocSize, uint32_t, true>; 180 key()181 KeyType* key() { return &fKey; } 182 183 private: 184 SkSTArray<kPreAllocSize, uint32_t, true> fKey; 185 uint32_t fInitialKeyLength = 0; 186 }; 187 188 #endif 189