| /* |
| * Copyright 2025 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef skgpu_graphite_PipelineManager_DEFINED |
| #define skgpu_graphite_PipelineManager_DEFINED |
| |
| #include "include/core/SkRefCnt.h" |
| #include "include/private/SkEnumBitMask.h" |
| #include "src/core/SkSpinlock.h" |
| #include "src/core/SkTHash.h" |
| |
| namespace skgpu { |
| class UniqueKey; |
| } |
| |
| class SkExecutor; |
| |
| namespace skgpu::graphite { |
| |
| class GraphicsPipeline; |
| class GraphicsPipelineDesc; |
| class GraphicsPipelineHandle; |
| enum class PipelineCreationFlags : uint8_t; |
| class PipelineCreationTask; |
| class RuntimeEffectDictionary; |
| class SharedContext; |
| struct RenderPassDesc; |
| |
| class PipelineManager { |
| public: |
| PipelineManager(SkExecutor* executor); |
| ~PipelineManager(); |
| |
| // If an existing Pipeline is found, it is just wrapped in a Handle and returned. |
| // Otherwise, a compilation task is created and queued up for execution. |
| // If no Executor is provided the compilations will occur synchronously, in-line. |
| GraphicsPipelineHandle createHandle( |
| SharedContext*, |
| sk_sp<const RuntimeEffectDictionary> runtimeDict, |
| const GraphicsPipelineDesc&, |
| const RenderPassDesc&, |
| SkEnumBitMask<PipelineCreationFlags>); |
| |
| sk_sp<GraphicsPipeline> resolveHandle(const GraphicsPipelineHandle&); |
| |
| // Wait for any in-flight tasks to complete. Additionally, disable the addition of any |
| // more threaded tasks. |
| void shutDown() SK_EXCLUDES(fSpinLock); |
| |
| #if defined(GPU_TEST_UTILS) |
| void wait_TestOnly() SK_EXCLUDES(fSpinLock); |
| |
| struct Stats { |
| // The number of times we find a pre-existing task for a Pipeline |
| int fNumPreemptivelyFoundTasks = 0; |
| int fNumTasksCreated = 0; |
| }; |
| |
| Stats getStats() const SK_EXCLUDES(fSpinLock); |
| #endif |
| |
| private: |
| enum class Priority { kHigh = 0, kLow = 1 }; |
| |
| sk_sp<PipelineCreationTask> findOrCreateTask( |
| SharedContext*, |
| sk_sp<const RuntimeEffectDictionary>, |
| const UniqueKey& pipelineKey, |
| const GraphicsPipelineDesc&, |
| const RenderPassDesc&, |
| Priority) SK_EXCLUDES(fSpinLock); |
| |
| void addTaskToWorkList(SharedContext*, |
| sk_sp<PipelineCreationTask>, |
| Priority) SK_EXCLUDES(fSpinLock); |
| |
| void removeTask(const sk_sp<PipelineCreationTask>&) SK_EXCLUDES(fSpinLock); |
| |
| void potentiallyWaitOn(const sk_sp<PipelineCreationTask>&) SK_EXCLUDES(fSpinLock); |
| |
| sk_sp<PipelineCreationTask> getWork(bool inclInProgress) SK_EXCLUDES(fSpinLock); |
| void wait() SK_EXCLUDES(fSpinLock); |
| |
| // Returns true if compilation occurred; false otherwise. |
| // All callers must hold a ref on the PipelineCreationTask. |
| static bool InlineCompile(const sk_sp<PipelineCreationTask>&) SK_EXCLUDES(fSpinLock); |
| |
| struct Traits { |
| static const UniqueKey& GetKey(const sk_sp<PipelineCreationTask>&); |
| static uint32_t Hash(const UniqueKey& pipelineKey); |
| }; |
| using TaskMap = skia_private::THashTable<sk_sp<PipelineCreationTask>, UniqueKey, Traits>; |
| |
| mutable SkSpinlock fSpinLock; |
| |
| TaskMap fActiveTasks SK_GUARDED_BY(fSpinLock); |
| |
| #if defined(GPU_TEST_UTILS) |
| Stats fStats SK_GUARDED_BY(fSpinLock); |
| #endif |
| |
| // The executor is obtained from ContextOptions. It is up to the client to ensure it |
| // exists past the Context's destruction. The Context does call PipelineManager::shutDown |
| // from its destructor to end its use. |
| SkExecutor* fExecutor SK_GUARDED_BY(fSpinLock) = nullptr; |
| }; |
| |
| } // namespace skgpu::graphite |
| |
| #endif // skgpu_graphite_PipelineManager_DEFINED |