xref: /aosp_15_r20/external/skia/src/gpu/ganesh/gl/GrGLGpuProgramCache.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "include/core/SkData.h"
8 #include "include/core/SkRefCnt.h"
9 #include "include/gpu/ganesh/GrDirectContext.h"
10 #include "include/private/base/SkAssert.h"
11 #include "include/private/gpu/ganesh/GrTypesPriv.h"
12 #include "src/core/SkLRUCache.h"
13 #include "src/gpu/ganesh/GrCaps.h"
14 #include "src/gpu/ganesh/GrDirectContextPriv.h"
15 #include "src/gpu/ganesh/GrProgramDesc.h"
16 #include "src/gpu/ganesh/gl/GrGLGpu.h"
17 #include "src/gpu/ganesh/gl/GrGLProgram.h"
18 #include "src/gpu/ganesh/gl/builders/GrGLProgramBuilder.h"
19 
20 #include <memory>
21 #include <utility>
22 
23 class GrProgramInfo;
24 
25 struct GrGLGpu::ProgramCache::Entry {
EntryGrGLGpu::ProgramCache::Entry26     Entry(sk_sp<GrGLProgram> program)
27         : fProgram(std::move(program)) {}
28 
EntryGrGLGpu::ProgramCache::Entry29     Entry(const GrGLPrecompiledProgram& precompiledProgram)
30         : fPrecompiledProgram(precompiledProgram) {}
31 
32     sk_sp<GrGLProgram> fProgram;
33     GrGLPrecompiledProgram fPrecompiledProgram;
34 };
35 
ProgramCache(int runtimeProgramCacheSize)36 GrGLGpu::ProgramCache::ProgramCache(int runtimeProgramCacheSize)
37     : fMap(runtimeProgramCacheSize) {
38 }
39 
~ProgramCache()40 GrGLGpu::ProgramCache::~ProgramCache() {}
41 
abandon()42 void GrGLGpu::ProgramCache::abandon() {
43     fMap.foreach([](GrProgramDesc*, std::unique_ptr<Entry>* e) {
44         if ((*e)->fProgram) {
45             (*e)->fProgram->abandon();
46         }
47     });
48 
49     this->reset();
50 }
51 
reset()52 void GrGLGpu::ProgramCache::reset() {
53     fMap.reset();
54 }
55 
findOrCreateProgram(GrDirectContext * dContext,const GrProgramInfo & programInfo)56 sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* dContext,
57                                                               const GrProgramInfo& programInfo) {
58     const GrCaps* caps = dContext->priv().caps();
59 
60     GrProgramDesc desc = caps->makeDesc(/*renderTarget*/nullptr, programInfo);
61     if (!desc.isValid()) {
62         GrCapsDebugf(caps, "Failed to gl program descriptor!\n");
63         return nullptr;
64     }
65 
66     Stats::ProgramCacheResult stat;
67     sk_sp<GrGLProgram> tmp = this->findOrCreateProgramImpl(dContext, desc, programInfo, &stat);
68     if (!tmp) {
69         fStats.incNumInlineCompilationFailures();
70     } else {
71         fStats.incNumInlineProgramCacheResult(stat);
72     }
73 
74     return tmp;
75 }
76 
findOrCreateProgram(GrDirectContext * dContext,const GrProgramDesc & desc,const GrProgramInfo & programInfo,Stats::ProgramCacheResult * stat)77 sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* dContext,
78                                                               const GrProgramDesc& desc,
79                                                               const GrProgramInfo& programInfo,
80                                                               Stats::ProgramCacheResult* stat) {
81     sk_sp<GrGLProgram> tmp = this->findOrCreateProgramImpl(dContext, desc, programInfo, stat);
82     if (!tmp) {
83         fStats.incNumPreCompilationFailures();
84     } else {
85         fStats.incNumPreProgramCacheResult(*stat);
86     }
87 
88     return tmp;
89 }
90 
findOrCreateProgramImpl(GrDirectContext * dContext,const GrProgramDesc & desc,const GrProgramInfo & programInfo,Stats::ProgramCacheResult * stat)91 sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgramImpl(GrDirectContext* dContext,
92                                                                   const GrProgramDesc& desc,
93                                                                   const GrProgramInfo& programInfo,
94                                                                   Stats::ProgramCacheResult* stat) {
95     *stat = Stats::ProgramCacheResult::kHit;
96     std::unique_ptr<Entry>* entry = fMap.find(desc);
97     if (entry && !(*entry)->fProgram) {
98         // We've pre-compiled the GL program, but don't have the GrGLProgram scaffolding
99         const GrGLPrecompiledProgram* precompiledProgram = &((*entry)->fPrecompiledProgram);
100         SkASSERT(precompiledProgram->fProgramID != 0);
101         (*entry)->fProgram = GrGLProgramBuilder::CreateProgram(dContext, desc, programInfo,
102                                                                precompiledProgram);
103         if (!(*entry)->fProgram) {
104             // Should we purge the program ID from the cache at this point?
105             SkDEBUGFAIL("Couldn't create program from precompiled program");
106             fStats.incNumCompilationFailures();
107             return nullptr;
108         }
109         fStats.incNumPartialCompilationSuccesses();
110         *stat = Stats::ProgramCacheResult::kPartial;
111     } else if (!entry) {
112         // We have a cache miss
113         sk_sp<GrGLProgram> program = GrGLProgramBuilder::CreateProgram(dContext, desc, programInfo);
114         if (!program) {
115             fStats.incNumCompilationFailures();
116             return nullptr;
117         }
118         fStats.incNumCompilationSuccesses();
119         entry = fMap.insert(desc, std::make_unique<Entry>(std::move(program)));
120         *stat = Stats::ProgramCacheResult::kMiss;
121     }
122 
123     return (*entry)->fProgram;
124 }
125 
precompileShader(GrDirectContext * dContext,const SkData & key,const SkData & data)126 bool GrGLGpu::ProgramCache::precompileShader(GrDirectContext* dContext,
127                                              const SkData& key,
128                                              const SkData& data) {
129     GrProgramDesc desc;
130     if (!GrProgramDesc::BuildFromData(&desc, key.data(), key.size())) {
131         return false;
132     }
133 
134     std::unique_ptr<Entry>* entry = fMap.find(desc);
135     if (entry) {
136         // We've already seen/compiled this shader
137         return true;
138     }
139 
140     GrGLPrecompiledProgram precompiledProgram;
141     if (!GrGLProgramBuilder::PrecompileProgram(dContext, &precompiledProgram, data)) {
142         return false;
143     }
144 
145     fMap.insert(desc, std::make_unique<Entry>(precompiledProgram));
146     return true;
147 }
148