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/GrContext.h"
9#include "src/core/SkLRUCache.h"
10#include "src/gpu/GrCaps.h"
11#include "src/gpu/GrContextThreadSafeProxyPriv.h"
12#include "src/gpu/GrProgramDesc.h"
13#include "src/gpu/GrProgramInfo.h"
14#include "src/gpu/GrRecordingContextPriv.h"
15#include "src/gpu/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 */
21class GrDDLContext final : public GrContext {
22public:
23 GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)
24 : INHERITED(std::move(proxy)) {
25 }
26
27 ~GrDDLContext() override {}
28
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 void releaseResourcesAndAbandonContext() override {
35 SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense
36 INHERITED::releaseResourcesAndAbandonContext();
37 }
38
39 void freeGpuResources() override {
40 // freeing resources in a DDL Recorder doesn't make a whole lot of sense but some of
41 // our tests do it anyways
42 }
43
44private:
45 // TODO: Here we're pretending this isn't derived from GrContext. Switch this to be derived from
46 // GrRecordingContext!
47 GrDirectContext* asDirectContext() override { return nullptr; }
48
49 bool init() override {
50 if (!INHERITED::init()) {
51 return false;
52 }
53
54 // DDL contexts/drawing managers always sort the oplists and attempt to reduce opsTask
55 // splitting.
56 this->setupDrawingManager(true, true);
57
58 return true;
59 }
60
61 GrAtlasManager* onGetAtlasManager() override {
62 SkASSERT(0); // the DDL Recorders should never invoke this
63 return nullptr;
64 }
65
66 GrSmallPathAtlasMgr* onGetSmallPathAtlasMgr() override {
67 SkASSERT(0); // DDL recorders should never invoke this
68 return nullptr;
69 }
70
71 // Add to the set of unique program infos required by this DDL
72 void recordProgramInfo(const GrProgramInfo* programInfo) final {
73 if (!programInfo) {
74 return;
75 }
76
77 const GrCaps* caps = this->caps();
78
79 if (this->backend() == GrBackendApi::kMetal ||
80 this->backend() == GrBackendApi::kDirect3D ||
81 this->backend() == GrBackendApi::kDawn) {
82 // Currently Metal, Direct3D, and Dawn require a live renderTarget to
83 // compute the key
84 return;
85 }
86
87 if (programInfo->requestedFeatures() & GrProcessor::CustomFeatures::kSampleLocations) {
88 // Sample locations require a live renderTarget to compute the key
89 return;
90 }
91
92 GrProgramDesc desc = caps->makeDesc(nullptr, *programInfo);
93 if (!desc.isValid()) {
94 return;
95 }
96
97 fProgramInfoMap.add(desc, programInfo);
98 }
99
100 void detachProgramData(SkTArray<ProgramData>* dst) final {
101 SkASSERT(dst->empty());
102
103 fProgramInfoMap.toArray(dst);
104 }
105
106
107private:
108 class ProgramInfoMap : public ::SkNoncopyable {
109 typedef const GrProgramDesc CacheKey;
110 typedef const GrProgramInfo* CacheValue;
111
112 public:
113 // All the programInfo data should be stored in the record-time arena so there is no
114 // need to ref them here or to delete them in the destructor.
115 ProgramInfoMap() : fMap(10) {}
116 ~ProgramInfoMap() {}
117
118 // TODO: this is doing a lot of reallocating of the ProgramDesc! Once the program descs
119 // are allocated in the record-time area there won't be a problem.
120 void add(CacheKey& desc, const GrProgramInfo* programInfo) {
121 SkASSERT(desc.isValid());
122
123 const CacheValue* preExisting = fMap.find(desc);
124 if (preExisting) {
125 return;
126 }
127
128 fMap.insert(desc, programInfo);
129 }
130
131 void toArray(SkTArray<ProgramData>* dst) {
132 fMap.foreach([dst](CacheKey* programDesc, CacheValue* programInfo) {
133 // TODO: remove this allocation once the program descs are stored
134 // in the record-time arena.
135 dst->emplace_back(std::make_unique<const GrProgramDesc>(*programDesc),
136 *programInfo);
137 });
138 }
139
140 private:
141 struct DescHash {
142 uint32_t operator()(CacheKey& desc) const {
143 return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
144 }
145 };
146
147 SkLRUCache<CacheKey, CacheValue, DescHash> fMap;
148 };
149
150 ProgramInfoMap fProgramInfoMap;
151
152 typedef GrContext INHERITED;
153};
154
155sk_sp<GrRecordingContext> GrRecordingContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) {
156 sk_sp<GrRecordingContext> context(new GrDDLContext(std::move(proxy)));
157
158 if (!context->init()) {
159 return nullptr;
160 }
161 return context;
162}
163