| /* | |
| * Copyright 2018 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "include/gpu/GrRecordingContext.h" | |
| #include "src/core/SkLRUCache.h" | |
| #include "src/gpu/GrCaps.h" | |
| #include "src/gpu/GrContextThreadSafeProxyPriv.h" | |
| #include "src/gpu/GrProgramDesc.h" | |
| #include "src/gpu/GrProgramInfo.h" | |
| #include "src/gpu/GrRecordingContextPriv.h" | |
| #include "src/gpu/effects/GrSkSLFP.h" | |
| /** | |
| * The DDL Context is the one in effect during DDL Recording. It isn't backed by a GrGPU and | |
| * cannot allocate any GPU resources. | |
| */ | |
| class GrDDLContext final : public GrRecordingContext { | |
| public: | |
| GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy) | |
| : INHERITED(std::move(proxy), true) { | |
| } | |
| ~GrDDLContext() override {} | |
| void abandonContext() override { | |
| SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense | |
| INHERITED::abandonContext(); | |
| } | |
| private: | |
| // Add to the set of unique program infos required by this DDL | |
| void recordProgramInfo(const GrProgramInfo* programInfo) final { | |
| if (!programInfo) { | |
| return; | |
| } | |
| const GrCaps* caps = this->caps(); | |
| if (this->backend() == GrBackendApi::kMetal || | |
| this->backend() == GrBackendApi::kDirect3D || | |
| this->backend() == GrBackendApi::kDawn) { | |
| // Currently Metal, Direct3D, and Dawn require a live renderTarget to | |
| // compute the key | |
| return; | |
| } | |
| GrProgramDesc desc = caps->makeDesc(nullptr, *programInfo); | |
| if (!desc.isValid()) { | |
| return; | |
| } | |
| fProgramInfoMap.add(desc, programInfo); | |
| } | |
| void detachProgramData(SkTArray<ProgramData>* dst) final { | |
| SkASSERT(dst->empty()); | |
| fProgramInfoMap.toArray(dst); | |
| } | |
| private: | |
| class ProgramInfoMap : public ::SkNoncopyable { | |
| typedef const GrProgramDesc CacheKey; | |
| typedef const GrProgramInfo* CacheValue; | |
| public: | |
| // All the programInfo data should be stored in the record-time arena so there is no | |
| // need to ref them here or to delete them in the destructor. | |
| ProgramInfoMap() : fMap(10) {} | |
| ~ProgramInfoMap() {} | |
| // TODO: this is doing a lot of reallocating of the ProgramDesc! Once the program descs | |
| // are allocated in the record-time area there won't be a problem. | |
| void add(CacheKey& desc, const GrProgramInfo* programInfo) { | |
| SkASSERT(desc.isValid()); | |
| const CacheValue* preExisting = fMap.find(desc); | |
| if (preExisting) { | |
| return; | |
| } | |
| fMap.insert(desc, programInfo); | |
| } | |
| void toArray(SkTArray<ProgramData>* dst) { | |
| fMap.foreach([dst](CacheKey* programDesc, CacheValue* programInfo) { | |
| // TODO: remove this allocation once the program descs are stored | |
| // in the record-time arena. | |
| dst->emplace_back(std::make_unique<const GrProgramDesc>(*programDesc), | |
| *programInfo); | |
| }); | |
| } | |
| private: | |
| struct DescHash { | |
| uint32_t operator()(CacheKey& desc) const { | |
| return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); | |
| } | |
| }; | |
| SkLRUCache<CacheKey, CacheValue, DescHash> fMap; | |
| }; | |
| ProgramInfoMap fProgramInfoMap; | |
| using INHERITED = GrRecordingContext; | |
| }; | |
| sk_sp<GrRecordingContext> GrRecordingContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) { | |
| sk_sp<GrRecordingContext> context(new GrDDLContext(std::move(proxy))); | |
| if (!context->init()) { | |
| return nullptr; | |
| } | |
| return context; | |
| } |