1 /*
2 * Copyright 2018 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 #include "include/gpu/GrRecordingContext.h"
9 #include "src/core/SkLRUCache.h"
10 #include "src/gpu/ganesh/GrCaps.h"
11 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
12 #include "src/gpu/ganesh/GrProgramDesc.h"
13 #include "src/gpu/ganesh/GrProgramInfo.h"
14 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
15 #include "src/gpu/ganesh/effects/GrSkSLFP.h"
16
17 /**
18 * The DDL Context is the one in effect during DDL Recording. It isn't backed by a GrGPU and
19 * cannot allocate any GPU resources.
20 */
21 class GrDDLContext final : public GrRecordingContext {
22 public:
GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)23 GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)
24 : INHERITED(std::move(proxy), true) {
25 }
26
~GrDDLContext()27 ~GrDDLContext() override {}
28
abandonContext()29 void abandonContext() override {
30 SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense
31 INHERITED::abandonContext();
32 }
33
34 private:
35 // Add to the set of unique program infos required by this DDL
recordProgramInfo(const GrProgramInfo * programInfo)36 void recordProgramInfo(const GrProgramInfo* programInfo) final {
37 if (!programInfo) {
38 return;
39 }
40
41 const GrCaps* caps = this->caps();
42
43 if (this->backend() == GrBackendApi::kMetal ||
44 this->backend() == GrBackendApi::kDirect3D ||
45 this->backend() == GrBackendApi::kDawn) {
46 // Currently Metal, Direct3D, and Dawn require a live renderTarget to
47 // compute the key
48 return;
49 }
50
51 GrProgramDesc desc = caps->makeDesc(nullptr, *programInfo);
52 if (!desc.isValid()) {
53 return;
54 }
55
56 fProgramInfoMap.add(desc, programInfo);
57 }
58
detachProgramData(SkTArray<ProgramData> * dst)59 void detachProgramData(SkTArray<ProgramData>* dst) final {
60 SkASSERT(dst->empty());
61
62 fProgramInfoMap.toArray(dst);
63 }
64
65
66 private:
67 class ProgramInfoMap : public ::SkNoncopyable {
68 typedef const GrProgramDesc CacheKey;
69 typedef const GrProgramInfo* CacheValue;
70
71 public:
72 // All the programInfo data should be stored in the record-time arena so there is no
73 // need to ref them here or to delete them in the destructor.
ProgramInfoMap()74 ProgramInfoMap() : fMap(10) {}
~ProgramInfoMap()75 ~ProgramInfoMap() {}
76
77 // TODO: this is doing a lot of reallocating of the ProgramDesc! Once the program descs
78 // are allocated in the record-time area there won't be a problem.
add(CacheKey & desc,const GrProgramInfo * programInfo)79 void add(CacheKey& desc, const GrProgramInfo* programInfo) {
80 SkASSERT(desc.isValid());
81
82 const CacheValue* preExisting = fMap.find(desc);
83 if (preExisting) {
84 return;
85 }
86
87 fMap.insert(desc, programInfo);
88 }
89
toArray(SkTArray<ProgramData> * dst)90 void toArray(SkTArray<ProgramData>* dst) {
91 fMap.foreach([dst](CacheKey* programDesc, CacheValue* programInfo) {
92 // TODO: remove this allocation once the program descs are stored
93 // in the record-time arena.
94 dst->emplace_back(std::make_unique<const GrProgramDesc>(*programDesc),
95 *programInfo);
96 });
97 }
98
99 private:
100 struct DescHash {
operator ()GrDDLContext::ProgramInfoMap::DescHash101 uint32_t operator()(CacheKey& desc) const {
102 return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
103 }
104 };
105
106 SkLRUCache<CacheKey, CacheValue, DescHash> fMap;
107 };
108
109 ProgramInfoMap fProgramInfoMap;
110
111 using INHERITED = GrRecordingContext;
112 };
113
MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy)114 sk_sp<GrRecordingContext> GrRecordingContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) {
115 sk_sp<GrRecordingContext> context(new GrDDLContext(std::move(proxy)));
116
117 if (!context->init()) {
118 return nullptr;
119 }
120 return context;
121 }
122