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
17struct 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
28GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu)
29 : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize)
30 , fGpu(gpu) {}
31
32GrGLGpu::ProgramCache::~ProgramCache() {}
33
34void 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
44void GrGLGpu::ProgramCache::reset() {
45 fMap.reset();
46}
47
48sk_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
69sk_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
105bool 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