| /* |
| * 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)) { |
| } |
| |
| ~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; |
| } |
| |
| if (programInfo->requestedFeatures() & GrProcessor::CustomFeatures::kSampleLocations) { |
| // Sample locations 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; |
| } |