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