1 /*
2  * Copyright 2019 Google LLC.
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 GrPersistentCacheEntry_DEFINED
9 #define GrPersistentCacheEntry_DEFINED
10 
11 #include "include/core/SkData.h"
12 #include "include/private/GrTypesPriv.h"
13 #include "src/core/SkReadBuffer.h"
14 #include "src/core/SkWriteBuffer.h"
15 #include "src/sksl/SkSLString.h"
16 #include "src/sksl/ir/SkSLProgram.h"
17 
18 // The GrPersistentCache stores opaque blobs, as far as clients are concerned. It's helpful to
19 // inspect certain kinds of cached data within our tools, so for those cases (GLSL, SPIR-V), we
20 // put the serialization logic here, to be shared by the backend code and the tool code.
21 namespace GrPersistentCacheUtils {
22 
23 struct ShaderMetadata {
24     SkSL::Program::Settings* fSettings = nullptr;
25     SkTArray<SkSL::String> fAttributeNames;
26     bool fHasCustomColorOutput = false;
27     bool fHasSecondaryColorOutput = false;
28 };
29 
30 // Increment this whenever the serialization format of cached shaders changes
31 static constexpr int kCurrentVersion = 2;
32 
33 static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
34                                               const SkSL::String shaders[],
35                                               const SkSL::Program::Inputs inputs[],
36                                               int numInputs,
37                                               const ShaderMetadata* meta = nullptr) {
38     // For consistency (so tools can blindly pack and unpack cached shaders), we always write
39     // kGrShaderTypeCount inputs. If the backend gives us fewer, we just replicate the last one.
40     SkASSERT(numInputs >= 1 && numInputs <= kGrShaderTypeCount);
41 
42     SkBinaryWriteBuffer writer;
43     writer.writeInt(kCurrentVersion);
44     writer.writeUInt(shaderType);
45     for (int i = 0; i < kGrShaderTypeCount; ++i) {
46         writer.writeByteArray(shaders[i].c_str(), shaders[i].size());
47         writer.writePad32(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs));
48     }
49     writer.writeBool(SkToBool(meta));
50     if (meta) {
51         writer.writeBool(SkToBool(meta->fSettings));
52         if (meta->fSettings) {
53             writer.writeBool(meta->fSettings->fFlipY);
54             writer.writeBool(meta->fSettings->fFragColorIsInOut);
55             writer.writeBool(meta->fSettings->fForceHighPrecision);
56         }
57 
58         writer.writeInt(meta->fAttributeNames.count());
59         for (const auto& attr : meta->fAttributeNames) {
60             writer.writeByteArray(attr.c_str(), attr.size());
61         }
62 
63         writer.writeBool(meta->fHasCustomColorOutput);
64         writer.writeBool(meta->fHasSecondaryColorOutput);
65     }
66     return writer.snapshotAsData();
67 }
68 
GetType(SkReadBuffer * reader)69 static SkFourByteTag GetType(SkReadBuffer* reader) {
70     constexpr SkFourByteTag kInvalidTag = ~0;
71     int version           = reader->readInt();
72     SkFourByteTag typeTag = reader->readUInt();
73     return reader->validate(version == kCurrentVersion) ? typeTag : kInvalidTag;
74 }
75 
76 static inline bool UnpackCachedShaders(SkReadBuffer* reader,
77                                        SkSL::String shaders[],
78                                        SkSL::Program::Inputs inputs[],
79                                        int numInputs,
80                                        ShaderMetadata* meta = nullptr) {
81     for (int i = 0; i < kGrShaderTypeCount; ++i) {
82         size_t shaderLen = 0;
83         const char* shaderBuf = static_cast<const char*>(reader->skipByteArray(&shaderLen));
84         if (shaderBuf) {
85             shaders[i].assign(shaderBuf, shaderLen);
86         }
87 
88         // GL, for example, only wants one set of Inputs
89         if (i < numInputs) {
90             reader->readPad32(&inputs[i], sizeof(inputs[i]));
91         } else {
92             reader->skip(sizeof(SkSL::Program::Inputs));
93         }
94     }
95     if (reader->readBool() && meta) {
96         SkASSERT(meta->fSettings != nullptr);
97 
98         if (reader->readBool()) {
99             meta->fSettings->fFlipY              = reader->readBool();
100             meta->fSettings->fFragColorIsInOut   = reader->readBool();
101             meta->fSettings->fForceHighPrecision = reader->readBool();
102         }
103 
104         meta->fAttributeNames.resize(reader->readInt());
105         for (auto& attr : meta->fAttributeNames) {
106             size_t attrLen = 0;
107             const char* attrName = static_cast<const char*>(reader->skipByteArray(&attrLen));
108             if (attrName) {
109                 attr.assign(attrName, attrLen);
110             }
111         }
112 
113         meta->fHasCustomColorOutput    = reader->readBool();
114         meta->fHasSecondaryColorOutput = reader->readBool();
115     }
116 
117     if (!reader->isValid()) {
118         for (int i = 0; i < kGrShaderTypeCount; ++i) {
119             shaders[i].clear();
120         }
121     }
122     return reader->isValid();
123 }
124 
125 }  // namespace GrPersistentCacheUtils
126 
127 #endif
128