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/gl/GrGLGpu.h" |
11 | |
12 | #include "include/gpu/GrContextOptions.h" |
13 | #include "include/gpu/GrDirectContext.h" |
14 | #include "src/gpu/GrContextPriv.h" |
15 | #include "src/gpu/GrProcessor.h" |
16 | #include "src/gpu/GrProgramDesc.h" |
17 | #include "src/gpu/gl/builders/GrGLProgramBuilder.h" |
18 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.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(GrGLGpu* gpu) |
32 | : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize) |
33 | , fGpu(gpu) {} |
34 | |
35 | GrGLGpu::ProgramCache::~ProgramCache() {} |
36 | |
37 | void GrGLGpu::ProgramCache::abandon() { |
38 | fMap.foreach([](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(GrRenderTarget* renderTarget, |
52 | const GrProgramInfo& programInfo) { |
53 | const GrCaps& caps = *fGpu->caps(); |
54 | |
55 | GrProgramDesc desc = caps.makeDesc(renderTarget, 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->findOrCreateProgram(renderTarget, desc, programInfo, &stat); |
63 | if (!tmp) { |
64 | fGpu->fStats.incNumInlineCompilationFailures(); |
65 | } else { |
66 | fGpu->fStats.incNumInlineProgramCacheResult(stat); |
67 | } |
68 | |
69 | return tmp; |
70 | } |
71 | |
72 | sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrRenderTarget* renderTarget, |
73 | const GrProgramDesc& desc, |
74 | const GrProgramInfo& programInfo, |
75 | Stats::ProgramCacheResult* stat) { |
76 | *stat = Stats::ProgramCacheResult::kHit; |
77 | std::unique_ptr<Entry>* entry = fMap.find(desc); |
78 | if (entry && !(*entry)->fProgram) { |
79 | // We've pre-compiled the GL program, but don't have the GrGLProgram scaffolding |
80 | const GrGLPrecompiledProgram* precompiledProgram = &((*entry)->fPrecompiledProgram); |
81 | SkASSERT(precompiledProgram->fProgramID != 0); |
82 | (*entry)->fProgram = GrGLProgramBuilder::CreateProgram(fGpu, renderTarget, desc, |
83 | programInfo, precompiledProgram); |
84 | if (!(*entry)->fProgram) { |
85 | // Should we purge the program ID from the cache at this point? |
86 | SkDEBUGFAIL("Couldn't create program from precompiled program" ); |
87 | fGpu->fStats.incNumCompilationFailures(); |
88 | return nullptr; |
89 | } |
90 | fGpu->fStats.incNumPartialCompilationSuccesses(); |
91 | *stat = Stats::ProgramCacheResult::kPartial; |
92 | } else if (!entry) { |
93 | // We have a cache miss |
94 | sk_sp<GrGLProgram> program = GrGLProgramBuilder::CreateProgram(fGpu, renderTarget, |
95 | desc, programInfo); |
96 | if (!program) { |
97 | fGpu->fStats.incNumCompilationFailures(); |
98 | return nullptr; |
99 | } |
100 | fGpu->fStats.incNumCompilationSuccesses(); |
101 | entry = fMap.insert(desc, std::make_unique<Entry>(std::move(program))); |
102 | *stat = Stats::ProgramCacheResult::kMiss; |
103 | } |
104 | |
105 | return (*entry)->fProgram; |
106 | } |
107 | |
108 | bool GrGLGpu::ProgramCache::precompileShader(const SkData& key, const SkData& data) { |
109 | GrProgramDesc desc; |
110 | if (!GrProgramDesc::BuildFromData(&desc, key.data(), key.size())) { |
111 | return false; |
112 | } |
113 | |
114 | std::unique_ptr<Entry>* entry = fMap.find(desc); |
115 | if (entry) { |
116 | // We've already seen/compiled this shader |
117 | return true; |
118 | } |
119 | |
120 | GrGLPrecompiledProgram precompiledProgram; |
121 | if (!GrGLProgramBuilder::PrecompileProgram(&precompiledProgram, fGpu, data)) { |
122 | return false; |
123 | } |
124 | |
125 | fMap.insert(desc, std::make_unique<Entry>(precompiledProgram)); |
126 | return true; |
127 | } |
128 | |