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 {
EntryGrGLGpu::ProgramCache::Entry18     Entry(sk_sp<GrGLProgram> program)
19         : fProgram(std::move(program)) {}
20 
EntryGrGLGpu::ProgramCache::Entry21     Entry(const GrGLPrecompiledProgram& precompiledProgram)
22         : fPrecompiledProgram(precompiledProgram) {}
23 
24     sk_sp<GrGLProgram> fProgram;
25     GrGLPrecompiledProgram fPrecompiledProgram;
26 };
27 
ProgramCache(GrGLGpu * gpu)28 GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu)
29     : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
30     , fGpu(gpu) {}
31 
~ProgramCache()32 GrGLGpu::ProgramCache::~ProgramCache() {}
33 
abandon()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 
reset()44 void GrGLGpu::ProgramCache::reset() {
45     fMap.reset();
46 }
47 
findOrCreateProgram(GrRenderTarget * renderTarget,const GrProgramInfo & programInfo)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 
findOrCreateProgram(GrRenderTarget * renderTarget,const GrProgramDesc & desc,const GrProgramInfo & programInfo,Stats::ProgramCacheResult * stat)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 
precompileShader(const SkData & key,const SkData & data)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