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