| /* | |
| * Copyright 2019 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 "include/gpu/GrContextThreadSafeProxy.h" | |
| #include "src/core/SkArenaAlloc.h" | |
| #include "src/gpu/GrAuditTrail.h" | |
| #include "src/gpu/GrCaps.h" | |
| #include "src/gpu/GrContextThreadSafeProxyPriv.h" | |
| #include "src/gpu/GrDrawingManager.h" | |
| #include "src/gpu/GrMemoryPool.h" | |
| #include "src/gpu/GrProgramDesc.h" | |
| #include "src/gpu/GrProxyProvider.h" | |
| #include "src/gpu/GrRecordingContextPriv.h" | |
| #include "src/gpu/SkGr.h" | |
| #include "src/gpu/SurfaceContext.h" | |
| #include "src/gpu/effects/GrSkSLFP.h" | |
| #include "src/gpu/text/GrTextBlob.h" | |
| #include "src/gpu/text/GrTextBlobCache.h" | |
| #if SK_GPU_V1 | |
| #include "src/gpu/ops/GrAtlasTextOp.h" | |
| #endif | |
| GrRecordingContext::ProgramData::ProgramData(std::unique_ptr<const GrProgramDesc> desc, | |
| const GrProgramInfo* info) | |
| : fDesc(std::move(desc)) | |
| , fInfo(info) { | |
| } | |
| GrRecordingContext::ProgramData::ProgramData(ProgramData&& other) | |
| : fDesc(std::move(other.fDesc)) | |
| , fInfo(other.fInfo) { | |
| } | |
| GrRecordingContext::ProgramData::~ProgramData() = default; | |
| GrRecordingContext::GrRecordingContext(sk_sp<GrContextThreadSafeProxy> proxy, bool ddlRecording) | |
| : INHERITED(std::move(proxy)) | |
| , fAuditTrail(new GrAuditTrail()) | |
| , fArenas(ddlRecording) { | |
| fProxyProvider = std::make_unique<GrProxyProvider>(this); | |
| } | |
| GrRecordingContext::~GrRecordingContext() { | |
| #if SK_GPU_V1 | |
| GrAtlasTextOp::ClearCache(); | |
| #endif | |
| } | |
| int GrRecordingContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const { | |
| GrBackendFormat format = | |
| this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType), | |
| GrRenderable::kYes); | |
| return this->caps()->maxRenderTargetSampleCount(format); | |
| } | |
| bool GrRecordingContext::init() { | |
| if (!INHERITED::init()) { | |
| return false; | |
| } | |
| #if SK_GPU_V1 | |
| GrPathRendererChain::Options prcOptions; | |
| prcOptions.fAllowPathMaskCaching = this->options().fAllowPathMaskCaching; | |
| #if GR_TEST_UTILS | |
| prcOptions.fGpuPathRenderers = this->options().fGpuPathRenderers; | |
| #endif | |
| // FIXME: Once this is removed from Chrome and Android, rename to fEnable"". | |
| if (this->options().fDisableDistanceFieldPaths) { | |
| prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; | |
| } | |
| #endif | |
| bool reduceOpsTaskSplitting = true; | |
| if (this->caps()->avoidReorderingRenderTasks()) { | |
| reduceOpsTaskSplitting = false; | |
| } else if (GrContextOptions::Enable::kYes == this->options().fReduceOpsTaskSplitting) { | |
| reduceOpsTaskSplitting = true; | |
| } else if (GrContextOptions::Enable::kNo == this->options().fReduceOpsTaskSplitting) { | |
| reduceOpsTaskSplitting = false; | |
| } | |
| fDrawingManager.reset(new GrDrawingManager(this, | |
| #if SK_GPU_V1 | |
| prcOptions, | |
| #endif | |
| reduceOpsTaskSplitting)); | |
| return true; | |
| } | |
| void GrRecordingContext::abandonContext() { | |
| INHERITED::abandonContext(); | |
| this->destroyDrawingManager(); | |
| } | |
| GrDrawingManager* GrRecordingContext::drawingManager() { | |
| return fDrawingManager.get(); | |
| } | |
| void GrRecordingContext::destroyDrawingManager() { | |
| fDrawingManager.reset(); | |
| } | |
| GrRecordingContext::Arenas::Arenas(SkArenaAlloc* recordTimeAllocator, | |
| GrSubRunAllocator* subRunAllocator) | |
| : fRecordTimeAllocator(recordTimeAllocator) | |
| , fRecordTimeSubRunAllocator(subRunAllocator) { | |
| // OwnedArenas should instantiate these before passing the bare pointer off to this struct. | |
| SkASSERT(subRunAllocator); | |
| } | |
| // Must be defined here so that std::unique_ptr can see the sizes of the various pools, otherwise | |
| // it can't generate a default destructor for them. | |
| GrRecordingContext::OwnedArenas::OwnedArenas(bool ddlRecording) : fDDLRecording(ddlRecording) {} | |
| GrRecordingContext::OwnedArenas::~OwnedArenas() {} | |
| GrRecordingContext::OwnedArenas& GrRecordingContext::OwnedArenas::operator=(OwnedArenas&& a) { | |
| fDDLRecording = a.fDDLRecording; | |
| fRecordTimeAllocator = std::move(a.fRecordTimeAllocator); | |
| fRecordTimeSubRunAllocator = std::move(a.fRecordTimeSubRunAllocator); | |
| return *this; | |
| } | |
| GrRecordingContext::Arenas GrRecordingContext::OwnedArenas::get() { | |
| if (!fRecordTimeAllocator && fDDLRecording) { | |
| // TODO: empirically determine a better number for SkArenaAlloc's firstHeapAllocation param | |
| fRecordTimeAllocator = std::make_unique<SkArenaAlloc>(1024); | |
| } | |
| if (!fRecordTimeSubRunAllocator) { | |
| fRecordTimeSubRunAllocator = std::make_unique<GrSubRunAllocator>(); | |
| } | |
| return {fRecordTimeAllocator.get(), fRecordTimeSubRunAllocator.get()}; | |
| } | |
| GrRecordingContext::OwnedArenas&& GrRecordingContext::detachArenas() { | |
| return std::move(fArenas); | |
| } | |
| GrTextBlobCache* GrRecordingContext::getTextBlobCache() { | |
| return fThreadSafeProxy->priv().getTextBlobCache(); | |
| } | |
| const GrTextBlobCache* GrRecordingContext::getTextBlobCache() const { | |
| return fThreadSafeProxy->priv().getTextBlobCache(); | |
| } | |
| GrThreadSafeCache* GrRecordingContext::threadSafeCache() { | |
| return fThreadSafeProxy->priv().threadSafeCache(); | |
| } | |
| const GrThreadSafeCache* GrRecordingContext::threadSafeCache() const { | |
| return fThreadSafeProxy->priv().threadSafeCache(); | |
| } | |
| void GrRecordingContext::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) { | |
| this->drawingManager()->addOnFlushCallbackObject(onFlushCBObject); | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| int GrRecordingContext::maxTextureSize() const { return this->caps()->maxTextureSize(); } | |
| int GrRecordingContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); } | |
| bool GrRecordingContext::colorTypeSupportedAsImage(SkColorType colorType) const { | |
| GrBackendFormat format = | |
| this->caps()->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType), | |
| GrRenderable::kNo); | |
| return format.isValid(); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| #ifdef SK_ENABLE_DUMP_GPU | |
| #include "src/utils/SkJSONWriter.h" | |
| void GrRecordingContext::dumpJSON(SkJSONWriter* writer) const { | |
| writer->beginObject(); | |
| #if GR_GPU_STATS | |
| writer->appendS32("path_masks_generated", this->stats()->numPathMasksGenerated()); | |
| writer->appendS32("path_mask_cache_hits", this->stats()->numPathMaskCacheHits()); | |
| #endif | |
| writer->endObject(); | |
| } | |
| #else | |
| void GrRecordingContext::dumpJSON(SkJSONWriter*) const { } | |
| #endif | |
| #if GR_TEST_UTILS | |
| #if GR_GPU_STATS | |
| void GrRecordingContext::Stats::dump(SkString* out) const { | |
| out->appendf("Num Path Masks Generated: %d\n", fNumPathMasksGenerated); | |
| out->appendf("Num Path Mask Cache Hits: %d\n", fNumPathMaskCacheHits); | |
| } | |
| void GrRecordingContext::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, | |
| SkTArray<double>* values) const { | |
| keys->push_back(SkString("path_masks_generated")); | |
| values->push_back(fNumPathMasksGenerated); | |
| keys->push_back(SkString("path_mask_cache_hits")); | |
| values->push_back(fNumPathMaskCacheHits); | |
| } | |
| void GrRecordingContext::DMSAAStats::dumpKeyValuePairs(SkTArray<SkString>* keys, | |
| SkTArray<double>* values) const { | |
| keys->push_back(SkString("dmsaa_render_passes")); | |
| values->push_back(fNumRenderPasses); | |
| keys->push_back(SkString("dmsaa_multisample_render_passes")); | |
| values->push_back(fNumMultisampleRenderPasses); | |
| for (const auto& [name, count] : fTriggerCounts) { | |
| keys->push_back(SkStringPrintf("dmsaa_trigger_%s", name.c_str())); | |
| values->push_back(count); | |
| } | |
| } | |
| void GrRecordingContext::DMSAAStats::dump() const { | |
| SkDebugf("DMSAA Render Passes: %d\n", fNumRenderPasses); | |
| SkDebugf("DMSAA Multisample Render Passes: %d\n", fNumMultisampleRenderPasses); | |
| if (!fTriggerCounts.empty()) { | |
| SkDebugf("DMSAA Triggers:\n"); | |
| for (const auto& [name, count] : fTriggerCounts) { | |
| SkDebugf(" %s: %d\n", name.c_str(), count); | |
| } | |
| } | |
| } | |
| void GrRecordingContext::DMSAAStats::merge(const DMSAAStats& stats) { | |
| fNumRenderPasses += stats.fNumRenderPasses; | |
| fNumMultisampleRenderPasses += stats.fNumMultisampleRenderPasses; | |
| for (const auto& [name, count] : stats.fTriggerCounts) { | |
| fTriggerCounts[name] += count; | |
| } | |
| } | |
| #endif // GR_GPU_STATS | |
| #endif // GR_TEST_UTILS | |