/* * 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 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* 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* 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(*programDesc), *programInfo); }); } private: struct DescHash { uint32_t operator()(CacheKey& desc) const { return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); } }; SkLRUCache fMap; }; ProgramInfoMap fProgramInfoMap; using INHERITED = GrRecordingContext; }; sk_sp GrRecordingContextPriv::MakeDDL(sk_sp proxy) { sk_sp context(new GrDDLContext(std::move(proxy))); if (!context->init()) { return nullptr; } return context; }