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