1 /*
2  * Copyright 2021 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 #include "src/gpu/GrPersistentCacheUtils.h"
9 
10 #include "include/private/SkSLString.h"
11 #include "src/core/SkReadBuffer.h"
12 #include "src/core/SkWriteBuffer.h"
13 
14 namespace GrPersistentCacheUtils {
15 
16 static constexpr int kCurrentVersion = 5;
17 
GetCurrentVersion()18 int GetCurrentVersion() {
19     // The persistent cache stores a copy of the SkSL::Program::Inputs struct. If you alter the
20     // Program::Inputs struct in any way, you must increment kCurrentVersion to invalidate the
21     // outdated persistent cache files. The KnownSkSLProgramInputs struct must also be updated to
22     // match the new contents of Program::Inputs.
23     struct KnownSkSLProgramInputs { bool height, flipY; };
24     static_assert(sizeof(SkSL::Program::Inputs) == sizeof(KnownSkSLProgramInputs));
25 
26     return kCurrentVersion;
27 }
28 
PackCachedShaders(SkFourByteTag shaderType,const SkSL::String shaders[],const SkSL::Program::Inputs inputs[],int numInputs,const ShaderMetadata * meta)29 sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
30                                 const SkSL::String shaders[],
31                                 const SkSL::Program::Inputs inputs[],
32                                 int numInputs,
33                                 const ShaderMetadata* meta) {
34     // For consistency (so tools can blindly pack and unpack cached shaders), we always write
35     // kGrShaderTypeCount inputs. If the backend gives us fewer, we just replicate the last one.
36     SkASSERT(numInputs >= 1 && numInputs <= kGrShaderTypeCount);
37 
38     SkBinaryWriteBuffer writer;
39     writer.writeInt(kCurrentVersion);
40     writer.writeUInt(shaderType);
41     for (int i = 0; i < kGrShaderTypeCount; ++i) {
42         writer.writeByteArray(shaders[i].c_str(), shaders[i].size());
43         writer.writePad32(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs));
44     }
45     writer.writeBool(SkToBool(meta));
46     if (meta) {
47         writer.writeBool(SkToBool(meta->fSettings));
48         if (meta->fSettings) {
49             writer.writeBool(meta->fSettings->fFlipY);
50             writer.writeBool(meta->fSettings->fFragColorIsInOut);
51             writer.writeBool(meta->fSettings->fForceHighPrecision);
52             writer.writeBool(meta->fSettings->fUsePushConstants);
53         }
54 
55         writer.writeInt(meta->fAttributeNames.count());
56         for (const auto& attr : meta->fAttributeNames) {
57             writer.writeByteArray(attr.c_str(), attr.size());
58         }
59 
60         writer.writeBool(meta->fHasCustomColorOutput);
61         writer.writeBool(meta->fHasSecondaryColorOutput);
62 
63         if (meta->fPlatformData) {
64             writer.writeByteArray(meta->fPlatformData->data(), meta->fPlatformData->size());
65         }
66     }
67     return writer.snapshotAsData();
68 }
69 
GetType(SkReadBuffer * reader)70 SkFourByteTag GetType(SkReadBuffer* reader) {
71     constexpr SkFourByteTag kInvalidTag = ~0;
72     int version           = reader->readInt();
73     SkFourByteTag typeTag = reader->readUInt();
74     return reader->validate(version == kCurrentVersion) ? typeTag : kInvalidTag;
75 }
76 
UnpackCachedShaders(SkReadBuffer * reader,SkSL::String shaders[],SkSL::Program::Inputs inputs[],int numInputs,ShaderMetadata * meta)77 bool UnpackCachedShaders(SkReadBuffer* reader,
78                          SkSL::String shaders[],
79                          SkSL::Program::Inputs inputs[],
80                          int numInputs,
81                          ShaderMetadata* meta) {
82     for (int i = 0; i < kGrShaderTypeCount; ++i) {
83         size_t shaderLen = 0;
84         const char* shaderBuf = static_cast<const char*>(reader->skipByteArray(&shaderLen));
85         if (shaderBuf) {
86             shaders[i].assign(shaderBuf, shaderLen);
87         }
88 
89         // GL, for example, only wants one set of Inputs
90         if (i < numInputs) {
91             reader->readPad32(&inputs[i], sizeof(inputs[i]));
92         } else {
93             reader->skip(sizeof(SkSL::Program::Inputs));
94         }
95     }
96     if (reader->readBool() && meta) {
97         SkASSERT(meta->fSettings != nullptr);
98 
99         if (reader->readBool()) {
100             meta->fSettings->fFlipY              = reader->readBool();
101             meta->fSettings->fFragColorIsInOut   = reader->readBool();
102             meta->fSettings->fForceHighPrecision = reader->readBool();
103             meta->fSettings->fUsePushConstants   = reader->readBool();
104         }
105 
106         meta->fAttributeNames.resize(reader->readInt());
107         for (auto& attr : meta->fAttributeNames) {
108             size_t attrLen = 0;
109             const char* attrName = static_cast<const char*>(reader->skipByteArray(&attrLen));
110             if (attrName) {
111                 attr.assign(attrName, attrLen);
112             }
113         }
114 
115         meta->fHasCustomColorOutput    = reader->readBool();
116         meta->fHasSecondaryColorOutput = reader->readBool();
117 
118         // a given platform will be responsible for reading its data
119     }
120 
121     if (!reader->isValid()) {
122         for (int i = 0; i < kGrShaderTypeCount; ++i) {
123             shaders[i].clear();
124         }
125     }
126     return reader->isValid();
127 }
128 
129 }  // namespace GrPersistentCacheUtils
130