blob: c691e797739e15cc04b143204286e01ce6eee8ee [file] [log] [blame]
joshualitt79f8fae2014-10-28 17:59:26 -07001/*
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
Brian Osmanf0de96f2021-02-26 13:54:11 -050011#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/private/GrTypesPriv.h"
13#include "include/private/SkTArray.h"
14#include "include/private/SkTo.h"
joshualitt79f8fae2014-10-28 17:59:26 -070015
Brian Osmanf0de96f2021-02-26 13:54:11 -050016#include <limits.h>
17
Robert Phillips03e4c952019-11-26 16:20:22 -050018class GrCaps;
Robert Phillips901aff02019-10-08 12:32:56 -040019class GrProgramInfo;
Robert Phillips03e4c952019-11-26 16:20:22 -050020class GrRenderTarget;
Brian Salomon94efbf52016-11-29 13:43:05 -050021class GrShaderCaps;
egdaniel5d8f69f2016-09-07 07:24:12 -070022
Brian Osmanf0de96f2021-02-26 13:54:11 -050023class GrKeyBuilder {
24public:
25 GrKeyBuilder() = default;
26 GrKeyBuilder(const GrKeyBuilder& other) = default;
27
28 void reset() { *this = GrKeyBuilder{}; }
29
30 void addBits(uint32_t numBits, uint32_t val, const char* label) {
31 SkASSERT(numBits > 0 && numBits <= 32);
32 SkASSERT(numBits == 32 || (val < (1u << numBits)));
33
34 SkDEBUGCODE(fDescription.appendf("%s: %u\n", label, val);)
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
50 void addBytes(uint32_t numBytes, const void* data, const char* label) {
51 // TODO: Make this smarter/faster?
52 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
53 for (; numBytes --> 0; bytes++) {
54 this->addBits(8, *bytes, label);
55 }
56 }
57
58 template <typename StringFunc>
59 void addString(StringFunc&& sf) {
60 #ifdef SK_DEBUG
61 fDescription.append(sf());
62 fDescription.append("\n");
63 #endif
64 }
65
66 void flush() {
67 if (fBitsUsed) {
68 fData.push_back(fCurValue);
69 fCurValue = 0;
70 fBitsUsed = 0;
71 }
72 }
73
74 bool empty() const { return fData.empty() && !fBitsUsed; }
75
76 const uint32_t* data() const {
77 SkASSERT(fBitsUsed == 0); // flush() must be called when construction is complete
78 return fData.begin();
79 }
80
81 size_t size() const {
82 return (fData.count() + (fBitsUsed ? 1 : 0)) * sizeof(uint32_t);
83 }
84
85 size_t sizeInBits() const {
86 return (fData.count() * sizeof(uint32_t) * CHAR_BIT) + fBitsUsed;
87 }
88
89 GrKeyBuilder& operator=(const GrKeyBuilder& other) = default;
90
91 bool operator==(const GrKeyBuilder& that) const {
92 return fBitsUsed == that.fBitsUsed &&
93 fCurValue == that.fCurValue &&
94 fData == that.fData;
95 }
96
97 bool operator!= (const GrKeyBuilder& other) const {
98 return !(*this == other);
99 }
100
101 void setData(const void* data, size_t length) {
102 SkASSERT(SkIsAlign4(length));
103 fData.reset(length / 4);
104 memcpy(fData.begin(), data, length);
105 }
106
107 SkString description() const {
108 #ifdef SK_DEBUG
109 return fDescription;
110 #else
111 return SkString{};
112 #endif
113 }
114
115private:
116 enum {
117 kHeaderSize = 1, // "header" in ::Build
118 kMaxPreallocProcessors = 8,
119 kIntsPerProcessor = 4, // This is an overestimate of the average effect key size.
120 kPreAllocSize = kHeaderSize +
121 kMaxPreallocProcessors * kIntsPerProcessor,
122 };
123
124 SkSTArray<kPreAllocSize, uint32_t, true> fData;
125 uint32_t fCurValue = 0;
126 uint32_t fBitsUsed = 0; // ... in current value
127
128 SkDEBUGCODE(SkString fDescription;)
129};
130
Robert Phillips373bda62019-11-12 13:30:05 -0500131/** This class is used to generate a generic program cache key. The Dawn, Metal and Vulkan
132 * backends derive backend-specific versions which add additional information.
133 */
joshualitt79f8fae2014-10-28 17:59:26 -0700134class GrProgramDesc {
135public:
Brian Osman9b510a32021-02-26 14:29:39 -0500136 GrProgramDesc(const GrProgramDesc& other) = default;
Robert Phillipsf6a0b452020-02-18 14:26:46 -0500137
Robert Phillips03e4c952019-11-26 16:20:22 -0500138 bool isValid() const { return !fKey.empty(); }
Brian Osmaned58e002019-09-06 14:42:43 -0400139
joshualitt79f8fae2014-10-28 17:59:26 -0700140 // Returns this as a uint32_t array to be used as a key in the program cache.
141 const uint32_t* asKey() const {
Brian Osmanf0de96f2021-02-26 13:54:11 -0500142 return fKey.data();
joshualitt79f8fae2014-10-28 17:59:26 -0700143 }
144
Greg Daniel2d2c09f2019-01-07 16:14:12 -0500145 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value.
146 uint32_t keyLength() const {
Brian Osmanf0de96f2021-02-26 13:54:11 -0500147 SkASSERT(0 == (fKey.size() % 4));
148 return fKey.size();
Greg Daniel2d2c09f2019-01-07 16:14:12 -0500149 }
joshualitt79f8fae2014-10-28 17:59:26 -0700150
Brian Osmanf0de96f2021-02-26 13:54:11 -0500151 SkString description() const { return fKey.description(); }
152
153 GrProgramDesc& operator= (const GrProgramDesc& other) = default;
joshualitt79f8fae2014-10-28 17:59:26 -0700154
bsalomon89d59882015-06-04 15:34:34 -0700155 bool operator== (const GrProgramDesc& that) const {
Brian Osmanf0de96f2021-02-26 13:54:11 -0500156 return this->fKey == that.fKey;
joshualitt79f8fae2014-10-28 17:59:26 -0700157 }
158
159 bool operator!= (const GrProgramDesc& other) const {
160 return !(*this == other);
161 }
162
Brian Osman9b510a32021-02-26 14:29:39 -0500163 uint32_t initialKeyLength() const { return fInitialKeyLength; }
Robert Phillipsc15e8902019-11-26 14:26:36 -0500164
Robert Phillipsd5c1f342019-10-14 09:50:05 -0400165protected:
Robert Phillips03e4c952019-11-26 16:20:22 -0500166 friend class GrDawnCaps;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500167 friend class GrD3DCaps;
Robert Phillips03e4c952019-11-26 16:20:22 -0500168 friend class GrGLCaps;
169 friend class GrMockCaps;
170 friend class GrMtlCaps;
171 friend class GrVkCaps;
172
173 friend class GrGLGpu; // for ProgramCache to access BuildFromData
174
175 // Creates an uninitialized key that must be populated by Build
176 GrProgramDesc() {}
177
178 /**
179 * Builds a program descriptor.
180 *
181 * @param desc The built descriptor
182 * @param renderTarget The target of the draw
183 * @param programInfo Program information need to build the key
184 * @param caps the caps
185 **/
Brian Salomonf7f54332020-07-28 09:23:35 -0400186 static bool Build(GrProgramDesc*, GrRenderTarget*, const GrProgramInfo&, const GrCaps&);
Robert Phillips03e4c952019-11-26 16:20:22 -0500187
John Stilesd3feb6f2020-07-23 18:18:12 -0400188 // This is strictly an OpenGL call since the other backends have additional data in their keys.
Robert Phillips03e4c952019-11-26 16:20:22 -0500189 static bool BuildFromData(GrProgramDesc* desc, const void* keyData, size_t keyLength) {
190 if (!SkTFitsIn<int>(keyLength)) {
191 return false;
192 }
Brian Osmanf0de96f2021-02-26 13:54:11 -0500193 desc->fKey.setData(keyData, keyLength);
Robert Phillips03e4c952019-11-26 16:20:22 -0500194 return true;
195 }
196
Brian Osmanf0de96f2021-02-26 13:54:11 -0500197 GrKeyBuilder& key() { return fKey; }
joshualitt79f8fae2014-10-28 17:59:26 -0700198
jvanverthd1e72872015-04-20 12:29:37 -0700199private:
Brian Osmanf0de96f2021-02-26 13:54:11 -0500200 GrKeyBuilder fKey;
Brian Osman9b510a32021-02-26 14:29:39 -0500201 uint32_t fInitialKeyLength = 0;
joshualitt79f8fae2014-10-28 17:59:26 -0700202};
203
204#endif