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 isValid()110 bool isValid() const { return !fKey.empty(); } reset()111 void reset() { *this = GrProgramDesc{}; } 112 113 // Returns this as a uint32_t array to be used as a key in the program cache. asKey()114 const uint32_t* asKey() const { 115 return fKey.data(); 116 } 117 118 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. keyLength()119 uint32_t keyLength() const { 120 return fKey.size() * sizeof(uint32_t); 121 } 122 123 bool operator== (const GrProgramDesc& that) const { 124 return this->fKey == that.fKey; 125 } 126 127 bool operator!= (const GrProgramDesc& other) const { 128 return !(*this == other); 129 } 130 initialKeyLength()131 uint32_t initialKeyLength() const { return fInitialKeyLength; } 132 133 // TODO(skia:11372): Incorporate this into caps interface (part of makeDesc, or a parallel 134 // function), so other backends can include their information in the description. 135 static SkString Describe(const GrProgramInfo&, const GrCaps&); 136 137 protected: 138 friend class GrDawnCaps; 139 friend class GrD3DCaps; 140 friend class GrGLCaps; 141 friend class GrMockCaps; 142 friend class GrMtlCaps; 143 friend class GrVkCaps; 144 145 friend class GrGLGpu; // for ProgramCache to access BuildFromData 146 friend class GrMtlResourceProvider; // for PipelineStateCache to access BuildFromData 147 148 // Creates an uninitialized key that must be populated by Build GrProgramDesc()149 GrProgramDesc() {} 150 151 /** 152 * Builds a program descriptor. 153 * 154 * @param desc The built descriptor 155 * @param programInfo Program information need to build the key 156 * @param caps the caps 157 **/ 158 static void Build(GrProgramDesc*, const GrProgramInfo&, const GrCaps&); 159 160 // 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)161 static bool BuildFromData(GrProgramDesc* desc, const void* keyData, size_t keyLength) { 162 if (!SkTFitsIn<int>(keyLength) || !SkIsAlign4(keyLength)) { 163 return false; 164 } 165 desc->fKey.reset(keyLength / 4); 166 memcpy(desc->fKey.begin(), keyData, keyLength); 167 return true; 168 } 169 170 enum { 171 kHeaderSize = 1, // "header" in ::Build 172 kMaxPreallocProcessors = 8, 173 kIntsPerProcessor = 4, // This is an overestimate of the average effect key size. 174 kPreAllocSize = kHeaderSize + 175 kMaxPreallocProcessors * kIntsPerProcessor, 176 }; 177 178 using KeyType = SkSTArray<kPreAllocSize, uint32_t, true>; 179 key()180 KeyType* key() { return &fKey; } 181 182 private: 183 SkSTArray<kPreAllocSize, uint32_t, true> fKey; 184 uint32_t fInitialKeyLength = 0; 185 }; 186 187 #endif 188