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
20struct 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
31GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu)
32 : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
33 , fGpu(gpu) {}
34
35GrGLGpu::ProgramCache::~ProgramCache() {}
36
37void 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
47void GrGLGpu::ProgramCache::reset() {
48 fMap.reset();
49}
50
51sk_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
72sk_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
108bool 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