blob: 72e893a657e3d45e43909e8eedec24e6c096e1c5 [file] [log] [blame]
/*
* 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/GrContext.h"
#include "src/core/SkLRUCache.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrContextThreadSafeProxyPriv.h"
#include "src/gpu/GrProgramDesc.h"
#include "src/gpu/GrProgramInfo.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 GrContext {
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();
}
void releaseResourcesAndAbandonContext() override {
SkASSERT(0); // abandoning in a DDL Recorder doesn't make a whole lot of sense
INHERITED::releaseResourcesAndAbandonContext();
}
void freeGpuResources() override {
// freeing resources in a DDL Recorder doesn't make a whole lot of sense but some of
// our tests do it anyways
}
private:
// TODO: Here we're pretending this isn't derived from GrContext. Switch this to be derived from
// GrRecordingContext!
GrContext* asDirectContext() override { return nullptr; }
bool init() override {
if (!INHERITED::init()) {
return false;
}
// DDL contexts/drawing managers always sort the oplists and attempt to reduce opsTask
// splitting.
this->setupDrawingManager(true, true);
return true;
}
GrAtlasManager* onGetAtlasManager() override {
SkASSERT(0); // the DDL Recorders should never invoke this
return nullptr;
}
// 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;
typedef GrContext INHERITED;
};
sk_sp<GrContext> GrContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) {
sk_sp<GrContext> context(new GrDDLContext(std::move(proxy)));
if (!context->init()) {
return nullptr;
}
return context;
}