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