• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2025 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/graphite/precompile/SerializationUtils.h"
9 
10 #include "include/core/SkFourByteTag.h"
11 #include "include/core/SkStream.h"
12 #include "src/base/SkAutoMalloc.h"
13 #include "src/gpu/graphite/Caps.h"
14 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
15 #include "src/gpu/graphite/PaintParamsKey.h"
16 #include "src/gpu/graphite/RenderPassDesc.h"
17 #include "src/gpu/graphite/Renderer.h"
18 #include "src/gpu/graphite/ShaderCodeDictionary.h"
19 #include "src/gpu/graphite/TextureInfoPriv.h"
20 
21 namespace skgpu::graphite {
22 
23 // This is the main control to version the serialized Pipelines (c.f. stream_is_blob)
24 static const int kCurrent_Version = 1;
25 
26 namespace {
27 
28 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'p', 'e' };
29 
stream_is_pipeline(SkStream * stream)30 [[nodiscard]] bool stream_is_pipeline(SkStream* stream) {
31     char magic[8];
32     static_assert(sizeof(kMagic) == sizeof(magic), "");
33 
34     if (stream->read(magic, sizeof(kMagic)) != sizeof(kMagic)) {
35         return false;
36     }
37 
38     if (0 != memcmp(magic, kMagic, sizeof(kMagic))) {
39         return false;
40     }
41 
42     uint32_t version;
43     if (!stream->readU32(&version)) {
44         return false;
45     }
46 
47     if (version != kCurrent_Version) {
48         return false;
49     }
50 
51     return true;
52 }
53 
serialize_graphics_pipeline_desc(ShaderCodeDictionary * shaderCodeDictionary,SkWStream * stream,const GraphicsPipelineDesc & pipelineDesc)54 [[nodiscard]] bool serialize_graphics_pipeline_desc(ShaderCodeDictionary* shaderCodeDictionary,
55                                                     SkWStream* stream,
56                                                     const GraphicsPipelineDesc& pipelineDesc) {
57     PaintParamsKey key = shaderCodeDictionary->lookup(pipelineDesc.paintParamsID());
58 
59     if (!stream->write32(static_cast<uint32_t>(pipelineDesc.renderStepID()))) {
60         return false;
61     }
62 
63     if (!key.isValid()) {
64         if (!stream->write32(0)) {
65             return false;
66         }
67         // Not all GraphicsPipeline have a valid PaintParamsKey
68         return true;
69     }
70 
71     const SkSpan<const uint32_t> keySpan = key.data();
72 
73     if (!key.isSerializable(shaderCodeDictionary)) {
74         return false;
75     }
76 
77     if (!stream->write32(SkToU32(keySpan.size()))) {
78         return false;
79     }
80     if (!stream->write(keySpan.data(), 4 * keySpan.size())) {
81         return false;
82     }
83     return true;
84 }
85 
deserialize_graphics_pipeline_desc(ShaderCodeDictionary * shaderCodeDictionary,SkStream * stream,GraphicsPipelineDesc * pipelineDesc)86 [[nodiscard]] bool deserialize_graphics_pipeline_desc(ShaderCodeDictionary* shaderCodeDictionary,
87                                                       SkStream* stream,
88                                                       GraphicsPipelineDesc* pipelineDesc) {
89     uint32_t tmp;
90     if (!stream->readU32(&tmp)) {
91         return false;
92     }
93 
94     if (tmp >= RenderStep::kNumRenderSteps) {
95         return false;
96     }
97     RenderStep::RenderStepID renderStepID = static_cast<RenderStep::RenderStepID>(tmp);
98 
99     if (!stream->readU32(&tmp)) {
100         return false;
101     }
102 
103     UniquePaintParamsID paintParamsID = UniquePaintParamsID::Invalid();
104     if (tmp) {
105         SkAutoMalloc storage(4 * tmp);
106         if (stream->read(storage.get(), 4 * tmp) != 4 * tmp) {
107             return false;
108         }
109 
110         PaintParamsKey ppk = PaintParamsKey(SkSpan<uint32_t>((uint32_t*) storage.get(), tmp));
111 
112         if (!ppk.isSerializable(shaderCodeDictionary)) {
113             return false;
114         }
115 
116         paintParamsID = shaderCodeDictionary->findOrCreate(ppk);
117     }
118 
119     *pipelineDesc = GraphicsPipelineDesc(renderStepID, paintParamsID);
120     return true;
121 }
122 
serialize_attachment_desc(const Caps * caps,SkWStream * stream,const AttachmentDesc & attachmentDesc)123 [[nodiscard]] bool serialize_attachment_desc(const Caps* caps,
124                                              SkWStream* stream,
125                                              const AttachmentDesc& attachmentDesc) {
126     if (!caps->serializeTextureInfo(attachmentDesc.fTextureInfo, stream)) {
127         return false;
128     }
129 
130     if (attachmentDesc.fTextureInfo.isValid()) {
131         if (!stream->write32(SkSetFourByteTag(static_cast<uint8_t>(attachmentDesc.fStoreOp),
132                                               static_cast<uint8_t>(attachmentDesc.fLoadOp),
133                                               0, 0))) {
134             return false;
135         }
136     }
137 
138     return true;
139 }
140 
deserialize_attachment_desc(const Caps * caps,SkStream * stream,AttachmentDesc * attachmentDesc)141 [[nodiscard]] bool deserialize_attachment_desc(const Caps* caps,
142                                                SkStream* stream,
143                                                AttachmentDesc* attachmentDesc) {
144     if (!caps->deserializeTextureInfo(stream, &attachmentDesc->fTextureInfo)) {
145         return false;
146     }
147 
148     if (attachmentDesc->fTextureInfo.isValid()) {
149         uint32_t tag;
150         if (!stream->readU32(&tag)) {
151             return false;
152         }
153 
154         attachmentDesc->fStoreOp = static_cast<StoreOp>(0xFF & (tag >> 24));
155         attachmentDesc->fLoadOp  = static_cast<LoadOp> (0xFF & (tag >> 16));
156     }
157 
158     return true;
159 }
160 
serialize_render_pass_desc(const Caps * caps,SkWStream * stream,const RenderPassDesc & renderPassDesc)161 [[nodiscard]] bool serialize_render_pass_desc(const Caps* caps,
162                                               SkWStream* stream,
163                                               const RenderPassDesc& renderPassDesc) {
164     if (!serialize_attachment_desc(caps, stream, renderPassDesc.fColorAttachment)) {
165         return false;
166     }
167 
168     for (int i = 0; i < 4; ++i) {
169         if (!stream->writeScalar(renderPassDesc.fClearColor[i])) {
170             return false;
171         }
172     }
173 
174     if (!serialize_attachment_desc(caps, stream, renderPassDesc.fColorResolveAttachment)) {
175         return false;
176     }
177     if (!serialize_attachment_desc(caps, stream, renderPassDesc.fDepthStencilAttachment)) {
178         return false;
179     }
180 
181     if (!stream->writeScalar(renderPassDesc.fClearDepth)) {
182         return false;
183     }
184     if (!stream->write32(renderPassDesc.fClearStencil)) {
185         return false;
186     }
187 
188     if (!stream->write32(SkSetFourByteTag(renderPassDesc.fWriteSwizzle[0],
189                                           renderPassDesc.fWriteSwizzle[1],
190                                           renderPassDesc.fWriteSwizzle[2],
191                                           renderPassDesc.fWriteSwizzle[3]))) {
192         return false;
193     }
194 
195     if (!stream->write32(renderPassDesc.fSampleCount)) {
196         return false;
197     }
198 
199     if (!stream->write8(static_cast<uint8_t>(renderPassDesc.fDstReadStrategyIfRequired))) {
200         return false;
201     }
202 
203     return true;
204 }
205 
deserialize_render_pass_desc(const Caps * caps,SkStream * stream,RenderPassDesc * renderPassDesc)206 [[nodiscard]] bool deserialize_render_pass_desc(const Caps* caps,
207                                                 SkStream* stream,
208                                                 RenderPassDesc* renderPassDesc) {
209     if (!deserialize_attachment_desc(caps, stream, &renderPassDesc->fColorAttachment)) {
210         return false;
211     }
212 
213     for (int i = 0; i < 4; ++i) {
214         if (!stream->readScalar(&renderPassDesc->fClearColor[i])) {
215             return false;
216         }
217     }
218 
219     if (!deserialize_attachment_desc(caps, stream, &renderPassDesc->fColorResolveAttachment)) {
220         return false;
221     }
222     if (!deserialize_attachment_desc(caps, stream, &renderPassDesc->fDepthStencilAttachment)) {
223         return false;
224     }
225 
226     if (!stream->readScalar(&renderPassDesc->fClearDepth)) {
227         return false;
228     }
229     if (!stream->readU32(&renderPassDesc->fClearStencil)) {
230         return false;
231     }
232 
233     uint32_t tag;
234     if (!stream->readU32(&tag)) {
235         return false;
236     }
237 
238     char tmpSwizzle[4] = {
239             (char) (0xFF & (tag >> 24)),
240             (char) (0xFF & (tag >> 16)),
241             (char) (0xFF & (tag >> 8)),
242             (char) (0xFF & (tag)),
243     };
244 
245     renderPassDesc->fWriteSwizzle = Swizzle(tmpSwizzle);
246 
247     if (!stream->readU32(&renderPassDesc->fSampleCount)) {
248         return false;
249     }
250 
251     uint8_t tmp8;
252     if (!stream->readU8(&tmp8)) {
253         return false;
254     }
255 
256     renderPassDesc->fDstReadStrategyIfRequired = static_cast<DstReadStrategy>(tmp8);
257 
258     return true;
259 }
260 
261 #define SK_BLOB_END_TAG SkSetFourByteTag('e', 'n', 'd', ' ')
262 
SerializePipelineDesc(const Caps * caps,ShaderCodeDictionary * shaderCodeDictionary,SkWStream * stream,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc)263 bool SerializePipelineDesc(const Caps* caps,
264                            ShaderCodeDictionary* shaderCodeDictionary,
265                            SkWStream* stream,
266                            const GraphicsPipelineDesc& pipelineDesc,
267                            const RenderPassDesc& renderPassDesc) {
268 
269     stream->write(kMagic, sizeof(kMagic));
270     stream->write32(kCurrent_Version);
271 
272     if (!serialize_graphics_pipeline_desc(shaderCodeDictionary, stream, pipelineDesc)) {
273         return false;
274     }
275 
276     if (!serialize_render_pass_desc(caps, stream, renderPassDesc)) {
277         return false;
278     }
279 
280     stream->write32(SK_BLOB_END_TAG);
281     return true;
282 }
283 
DeserializePipelineDesc(const Caps * caps,ShaderCodeDictionary * shaderCodeDictionary,SkStream * stream,GraphicsPipelineDesc * pipelineDesc,RenderPassDesc * renderPassDesc)284 bool DeserializePipelineDesc(const Caps* caps,
285                              ShaderCodeDictionary* shaderCodeDictionary,
286                              SkStream* stream,
287                              GraphicsPipelineDesc* pipelineDesc,
288                              RenderPassDesc* renderPassDesc) {
289     SkASSERT(stream);
290 
291     if (!stream_is_pipeline(stream)) {
292         return false;
293     }
294 
295     if (!deserialize_graphics_pipeline_desc(shaderCodeDictionary, stream, pipelineDesc)) {
296         return false;
297     }
298 
299     if (!deserialize_render_pass_desc(caps, stream, renderPassDesc)) {
300         return false;
301     }
302 
303     uint32_t tag;
304     if (!stream->readU32(&tag)) {
305         return false;
306     }
307 
308     if (tag != SK_BLOB_END_TAG) {
309         return false;
310     }
311 
312     return true;
313 }
314 
315 } // anonymous namespace
316 
PipelineDescToData(const Caps * caps,ShaderCodeDictionary * shaderCodeDictionary,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc)317 sk_sp<SkData> PipelineDescToData(const Caps* caps,
318                                  ShaderCodeDictionary* shaderCodeDictionary,
319                                  const GraphicsPipelineDesc& pipelineDesc,
320                                  const RenderPassDesc& renderPassDesc) {
321     SkDynamicMemoryWStream stream;
322 
323     if (!SerializePipelineDesc(caps,
324                                shaderCodeDictionary,
325                                &stream,
326                                pipelineDesc, renderPassDesc)) {
327         return nullptr;
328     }
329 
330     return stream.detachAsData();
331 }
332 
DataToPipelineDesc(const Caps * caps,ShaderCodeDictionary * shaderCodeDictionary,const SkData * data,GraphicsPipelineDesc * pipelineDesc,RenderPassDesc * renderPassDesc)333 bool DataToPipelineDesc(const Caps* caps,
334                         ShaderCodeDictionary* shaderCodeDictionary,
335                         const SkData* data,
336                         GraphicsPipelineDesc* pipelineDesc,
337                         RenderPassDesc* renderPassDesc) {
338     if (!data) {
339         return false;
340     }
341     SkMemoryStream stream(data->data(), data->size());
342 
343     if (!DeserializePipelineDesc(caps, shaderCodeDictionary, &stream,
344                                  pipelineDesc,
345                                  renderPassDesc)) {
346         return false;
347     }
348 
349     return true;
350 }
351 
352 #if defined(GPU_TEST_UTILS)
DumpPipelineDesc(const char * label,ShaderCodeDictionary * shaderCodeDictionary,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc)353 void DumpPipelineDesc(const char* label,
354                       ShaderCodeDictionary* shaderCodeDictionary,
355                       const GraphicsPipelineDesc& pipelineDesc,
356                       const RenderPassDesc& renderPassDesc) {
357     SkString pipelineStr = pipelineDesc.toString(shaderCodeDictionary);
358     SkString renderPassStr = renderPassDesc.toPipelineLabel();
359     SkDebugf("%s: %s - %s\n", label, pipelineStr.c_str(), renderPassStr.c_str());
360 }
361 
ComparePipelineDescs(const GraphicsPipelineDesc & a1,const RenderPassDesc & b1,const GraphicsPipelineDesc & a2,const RenderPassDesc & b2)362 bool ComparePipelineDescs(const GraphicsPipelineDesc& a1, const RenderPassDesc& b1,
363                           const GraphicsPipelineDesc& a2, const RenderPassDesc& b2) {
364     return (a1 == a2) && (b1 == b2);
365 }
366 #endif
367 
368 } // namespace skgpu::graphite
369