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