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([](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 
refProgram(GrGLGpu * gpu,GrRenderTarget * renderTarget,const GrProgramInfo & programInfo,GrPrimitiveType primitiveType)48 GrGLProgram* GrGLGpu::ProgramCache::refProgram(GrGLGpu* gpu,
49                                                GrRenderTarget* renderTarget,
50                                                const GrProgramInfo& programInfo,
51                                                GrPrimitiveType primitiveType) {
52     // TODO: can this be unified between GL, Vk and Mtl?
53     // Get GrGLProgramDesc
54     GrProgramDesc desc;
55     if (!GrProgramDesc::Build(&desc, renderTarget, programInfo, primitiveType, gpu)) {
56         GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n");
57         return nullptr;
58     }
59 
60     std::unique_ptr<Entry>* entry = fMap.find(desc);
61     if (entry && !(*entry)->fProgram) {
62         // We've pre-compiled the GL program, but don't have the GrGLProgram scaffolding
63         const GrGLPrecompiledProgram* precompiledProgram = &((*entry)->fPrecompiledProgram);
64         SkASSERT(precompiledProgram->fProgramID != 0);
65         GrGLProgram* program = GrGLProgramBuilder::CreateProgram(renderTarget, programInfo,
66                                                                  &desc, fGpu,
67                                                                  precompiledProgram);
68         if (nullptr == program) {
69             // Should we purge the program ID from the cache at this point?
70             SkDEBUGFAIL("Couldn't create program from precompiled program");
71             return nullptr;
72         }
73         (*entry)->fProgram.reset(program);
74     } else if (!entry) {
75         // We have a cache miss
76         GrGLProgram* program = GrGLProgramBuilder::CreateProgram(renderTarget, programInfo,
77                                                                  &desc, fGpu);
78         if (nullptr == program) {
79             return nullptr;
80         }
81         entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(sk_sp<GrGLProgram>(program))));
82     }
83 
84     return SkRef((*entry)->fProgram.get());
85 }
86 
precompileShader(const SkData & key,const SkData & data)87 bool GrGLGpu::ProgramCache::precompileShader(const SkData& key, const SkData& data) {
88     GrProgramDesc desc;
89     if (!GrProgramDesc::BuildFromData(&desc, key.data(), key.size())) {
90         return false;
91     }
92 
93     std::unique_ptr<Entry>* entry = fMap.find(desc);
94     if (entry) {
95         // We've already seen/compiled this shader
96         return true;
97     }
98 
99     GrGLPrecompiledProgram precompiledProgram;
100     if (!GrGLProgramBuilder::PrecompileProgram(&precompiledProgram, fGpu, data)) {
101         return false;
102     }
103 
104     fMap.insert(desc, std::unique_ptr<Entry>(new Entry(precompiledProgram)));
105     return true;
106 }
107