blob: 910751e6e63a2a46823c22f704d123003ac24294 [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 Osmanef3725f2021-03-04 10:44:41 -050023class GrProcessorKeyBuilder {
Brian Osmanf0de96f2021-02-26 13:54:11 -050024public:
Brian Osmane23c03d2021-03-05 14:58:25 -050025 GrProcessorKeyBuilder(SkTArray<uint32_t, true>* data) : fData(data) {}
Brian Osmanf0de96f2021-02-26 13:54:11 -050026
Brian Osmane23c03d2021-03-05 14:58:25 -050027 virtual ~GrProcessorKeyBuilder() {
28 // Ensure that flush was called before we went out of scope
29 SkASSERT(fBitsUsed == 0);
30 }
Brian Osmanf0de96f2021-02-26 13:54:11 -050031
Brian Osmane23c03d2021-03-05 14:58:25 -050032 virtual void addBits(uint32_t numBits, uint32_t val, const char* label) {
Brian Osmanf0de96f2021-02-26 13:54:11 -050033 SkASSERT(numBits > 0 && numBits <= 32);
34 SkASSERT(numBits == 32 || (val < (1u << numBits)));
35
Brian Osmanf0de96f2021-02-26 13:54:11 -050036 fCurValue |= (val << fBitsUsed);
37 fBitsUsed += numBits;
38
39 if (fBitsUsed >= 32) {
40 // Overflow, start a new working value
Brian Osmane23c03d2021-03-05 14:58:25 -050041 fData->push_back(fCurValue);
Brian Osmanf0de96f2021-02-26 13:54:11 -050042 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) {
Brian Osmanf0de96f2021-02-26 13:54:11 -050051 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
52 for (; numBytes --> 0; bytes++) {
53 this->addBits(8, *bytes, label);
54 }
55 }
56
Brian Osmanef3725f2021-03-04 10:44:41 -050057 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
Brian Osmane23c03d2021-03-05 14:58:25 -050065 virtual void appendComment(const char* comment) {}
Brian Osmanf0de96f2021-02-26 13:54:11 -050066
Brian Osmanef3725f2021-03-04 10:44:41 -050067 // 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.
Brian Osmanf0de96f2021-02-26 13:54:11 -050069 void flush() {
70 if (fBitsUsed) {
Brian Osmane23c03d2021-03-05 14:58:25 -050071 fData->push_back(fCurValue);
Brian Osmanf0de96f2021-02-26 13:54:11 -050072 fCurValue = 0;
73 fBitsUsed = 0;
74 }
75 }
76
Brian Osmanf0de96f2021-02-26 13:54:11 -050077private:
Brian Osmane23c03d2021-03-05 14:58:25 -050078 SkTArray<uint32_t, true>* fData;
Brian Osmanf0de96f2021-02-26 13:54:11 -050079 uint32_t fCurValue = 0;
80 uint32_t fBitsUsed = 0; // ... in current value
Brian Osmane23c03d2021-03-05 14:58:25 -050081};
Brian Osmanf0de96f2021-02-26 13:54:11 -050082
Brian Osmane23c03d2021-03-05 14:58:25 -050083class GrProcessorStringKeyBuilder : public GrProcessorKeyBuilder {
84public:
85 GrProcessorStringKeyBuilder(SkTArray<uint32_t, true>* data) : INHERITED(data) {}
86
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
92 void appendComment(const char* comment) override {
93 fDescription.appendf("%s\n", comment);
94 }
95
96 SkString description() const { return fDescription; }
97
98private:
99 using INHERITED = GrProcessorKeyBuilder;
100 SkString fDescription;
Brian Osmanf0de96f2021-02-26 13:54:11 -0500101};
102
Robert Phillips373bda62019-11-12 13:30:05 -0500103/** 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 */
joshualitt79f8fae2014-10-28 17:59:26 -0700106class GrProgramDesc {
107public:
Brian Osman9b510a32021-02-26 14:29:39 -0500108 GrProgramDesc(const GrProgramDesc& other) = default;
Robert Phillipsf6a0b452020-02-18 14:26:46 -0500109
Robert Phillips03e4c952019-11-26 16:20:22 -0500110 bool isValid() const { return !fKey.empty(); }
Brian Osmane23c03d2021-03-05 14:58:25 -0500111 void reset() { *this = GrProgramDesc{}; }
Brian Osmaned58e002019-09-06 14:42:43 -0400112
joshualitt79f8fae2014-10-28 17:59:26 -0700113 // Returns this as a uint32_t array to be used as a key in the program cache.
114 const uint32_t* asKey() const {
Brian Osmanf0de96f2021-02-26 13:54:11 -0500115 return fKey.data();
joshualitt79f8fae2014-10-28 17:59:26 -0700116 }
117
Greg Daniel2d2c09f2019-01-07 16:14:12 -0500118 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value.
119 uint32_t keyLength() const {
Brian Osmane23c03d2021-03-05 14:58:25 -0500120 return fKey.size() * sizeof(uint32_t);
Greg Daniel2d2c09f2019-01-07 16:14:12 -0500121 }
joshualitt79f8fae2014-10-28 17:59:26 -0700122
bsalomon89d59882015-06-04 15:34:34 -0700123 bool operator== (const GrProgramDesc& that) const {
Brian Osmanf0de96f2021-02-26 13:54:11 -0500124 return this->fKey == that.fKey;
joshualitt79f8fae2014-10-28 17:59:26 -0700125 }
126
127 bool operator!= (const GrProgramDesc& other) const {
128 return !(*this == other);
129 }
130
Brian Osman9b510a32021-02-26 14:29:39 -0500131 uint32_t initialKeyLength() const { return fInitialKeyLength; }
Robert Phillipsc15e8902019-11-26 14:26:36 -0500132
Brian Osmane23c03d2021-03-05 14:58:25 -0500133 // 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(GrRenderTarget*, const GrProgramInfo&, const GrCaps&);
136
Robert Phillipsd5c1f342019-10-14 09:50:05 -0400137protected:
Robert Phillips03e4c952019-11-26 16:20:22 -0500138 friend class GrDawnCaps;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500139 friend class GrD3DCaps;
Robert Phillips03e4c952019-11-26 16:20:22 -0500140 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
Jim Van Verth7d195ff2021-03-09 14:59:58 -0500146 friend class GrMtlResourceProvider; // for PipelineStateCache to access BuildFromData
Robert Phillips03e4c952019-11-26 16:20:22 -0500147
148 // Creates an uninitialized key that must be populated by Build
149 GrProgramDesc() {}
150
151 /**
152 * Builds a program descriptor.
153 *
154 * @param desc The built descriptor
155 * @param renderTarget The target of the draw
156 * @param programInfo Program information need to build the key
157 * @param caps the caps
158 **/
Brian Osmane23c03d2021-03-05 14:58:25 -0500159 static void Build(GrProgramDesc*, GrRenderTarget*, const GrProgramInfo&, const GrCaps&);
Robert Phillips03e4c952019-11-26 16:20:22 -0500160
John Stilesd3feb6f2020-07-23 18:18:12 -0400161 // This is strictly an OpenGL call since the other backends have additional data in their keys.
Robert Phillips03e4c952019-11-26 16:20:22 -0500162 static bool BuildFromData(GrProgramDesc* desc, const void* keyData, size_t keyLength) {
Brian Osmane23c03d2021-03-05 14:58:25 -0500163 if (!SkTFitsIn<int>(keyLength) || !SkIsAlign4(keyLength)) {
Robert Phillips03e4c952019-11-26 16:20:22 -0500164 return false;
165 }
Brian Osmane23c03d2021-03-05 14:58:25 -0500166 desc->fKey.reset(keyLength / 4);
167 memcpy(desc->fKey.begin(), keyData, keyLength);
Robert Phillips03e4c952019-11-26 16:20:22 -0500168 return true;
169 }
170
Brian Osmane23c03d2021-03-05 14:58:25 -0500171 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
181 KeyType* key() { return &fKey; }
joshualitt79f8fae2014-10-28 17:59:26 -0700182
jvanverthd1e72872015-04-20 12:29:37 -0700183private:
Brian Osmane23c03d2021-03-05 14:58:25 -0500184 SkSTArray<kPreAllocSize, uint32_t, true> fKey;
Brian Osman9b510a32021-02-26 14:29:39 -0500185 uint32_t fInitialKeyLength = 0;
joshualitt79f8fae2014-10-28 17:59:26 -0700186};
187
188#endif