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