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/private/GrTypesPriv.h" |
12 | #include "include/private/SkTArray.h" |
13 | #include "include/private/SkTo.h" |
14 | |
15 | class GrCaps; |
16 | class GrProgramInfo; |
17 | class GrRenderTarget; |
18 | class GrShaderCaps; |
19 | |
20 | /** This class is used to generate a generic program cache key. The Dawn, Metal and Vulkan |
21 | * backends derive backend-specific versions which add additional information. |
22 | */ |
23 | class GrProgramDesc { |
24 | public: |
25 | GrProgramDesc(const GrProgramDesc& other) : fKey(other.fKey) {} // for SkLRUCache |
26 | |
27 | bool isValid() const { return !fKey.empty(); } |
28 | |
29 | // Returns this as a uint32_t array to be used as a key in the program cache. |
30 | const uint32_t* asKey() const { |
31 | return reinterpret_cast<const uint32_t*>(fKey.begin()); |
32 | } |
33 | |
34 | // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. |
35 | uint32_t keyLength() const { |
36 | SkASSERT(0 == (fKey.count() % 4)); |
37 | return fKey.count(); |
38 | } |
39 | |
40 | GrProgramDesc& operator= (const GrProgramDesc& other) { |
41 | uint32_t keyLength = other.keyLength(); |
42 | fKey.reset(SkToInt(keyLength)); |
43 | memcpy(fKey.begin(), other.fKey.begin(), keyLength); |
44 | return *this; |
45 | } |
46 | |
47 | bool operator== (const GrProgramDesc& that) const { |
48 | if (this->keyLength() != that.keyLength()) { |
49 | return false; |
50 | } |
51 | |
52 | SkASSERT(SkIsAlign4(this->keyLength())); |
53 | int l = this->keyLength() >> 2; |
54 | const uint32_t* aKey = this->asKey(); |
55 | const uint32_t* bKey = that.asKey(); |
56 | for (int i = 0; i < l; ++i) { |
57 | if (aKey[i] != bKey[i]) { |
58 | return false; |
59 | } |
60 | } |
61 | return true; |
62 | } |
63 | |
64 | bool operator!= (const GrProgramDesc& other) const { |
65 | return !(*this == other); |
66 | } |
67 | |
68 | uint32_t initialKeyLength() const { return this->header().fInitialKeyLength; } |
69 | |
70 | protected: |
71 | friend class GrDawnCaps; |
72 | friend class GrD3DCaps; |
73 | friend class GrGLCaps; |
74 | friend class GrMockCaps; |
75 | friend class GrMtlCaps; |
76 | friend class GrVkCaps; |
77 | |
78 | friend class GrGLGpu; // for ProgramCache to access BuildFromData |
79 | |
80 | // Creates an uninitialized key that must be populated by Build |
81 | GrProgramDesc() {} |
82 | |
83 | /** |
84 | * Builds a program descriptor. |
85 | * |
86 | * @param desc The built descriptor |
87 | * @param renderTarget The target of the draw |
88 | * @param programInfo Program information need to build the key |
89 | * @param caps the caps |
90 | **/ |
91 | static bool Build(GrProgramDesc*, const GrRenderTarget*, const GrProgramInfo&, const GrCaps&); |
92 | |
93 | // This is strictly an OpenGL call since the other backends have additional data in their |
94 | // keys |
95 | static bool BuildFromData(GrProgramDesc* desc, const void* keyData, size_t keyLength) { |
96 | if (!SkTFitsIn<int>(keyLength)) { |
97 | return false; |
98 | } |
99 | desc->fKey.reset(SkToInt(keyLength)); |
100 | memcpy(desc->fKey.begin(), keyData, keyLength); |
101 | return true; |
102 | } |
103 | |
104 | // TODO: this should be removed and converted to just data added to the key |
105 | struct { |
106 | // Set to uniquely identify any swizzling of the shader's output color(s). |
107 | uint16_t ; |
108 | uint8_t ; // Can be packed into 4 bits if required. |
109 | uint8_t ; |
110 | // Set to uniquely identify the rt's origin, or 0 if the shader does not require this info. |
111 | uint32_t : 2; |
112 | uint32_t : 1; |
113 | uint32_t : 1; |
114 | uint32_t : 1; |
115 | // This is the key size (in bytes) after core key construction. It doesn't include any |
116 | // portions added by the platform-specific backends. |
117 | uint32_t : 27; |
118 | }; |
119 | static_assert(sizeof(KeyHeader) == 8); |
120 | |
121 | const KeyHeader& () const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } |
122 | |
123 | template<typename T, size_t OFFSET> T* atOffset() { |
124 | return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); |
125 | } |
126 | |
127 | template<typename T, size_t OFFSET> const T* atOffset() const { |
128 | return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); |
129 | } |
130 | |
131 | // The key, stored in fKey, is composed of two parts: |
132 | // 1. Header struct defined above. |
133 | // 2. A Backend specific payload which includes the per-processor keys. |
134 | enum KeyOffsets { |
135 | = 0, |
136 | = SkAlign4(sizeof(KeyHeader)), |
137 | // This is the offset into the backenend specific part of the key, which includes |
138 | // per-processor keys. |
139 | kProcessorKeysOffset = kHeaderOffset + kHeaderSize, |
140 | }; |
141 | |
142 | enum { |
143 | kMaxPreallocProcessors = 8, |
144 | kIntsPerProcessor = 4, // This is an overestimate of the average effect key size. |
145 | kPreAllocSize = kHeaderOffset + kHeaderSize + |
146 | kMaxPreallocProcessors * sizeof(uint32_t) * kIntsPerProcessor, |
147 | }; |
148 | |
149 | SkSTArray<kPreAllocSize, uint8_t, true>& key() { return fKey; } |
150 | |
151 | private: |
152 | SkSTArray<kPreAllocSize, uint8_t, true> fKey; |
153 | }; |
154 | |
155 | #endif |
156 | |