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 "GrGLGpu.h"
9 
10 #include "builders/GrGLProgramBuilder.h"
11 #include "GrProcessor.h"
12 #include "GrProgramDesc.h"
13 #include "GrGLPathRendering.h"
14 #include "glsl/GrGLSLFragmentProcessor.h"
15 #include "glsl/GrGLSLProgramDataManager.h"
16 #include "SkTSearch.h"
17 
18 #ifdef PROGRAM_CACHE_STATS
19 // Display program cache usage
20 static const bool c_DisplayCache{false};
21 #endif
22 
23 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
24 
25 struct GrGLGpu::ProgramCache::Entry {
EntryGrGLGpu::ProgramCache::Entry26     Entry(sk_sp<GrGLProgram> program) : fProgram(std::move(program)) {}
27 
28     sk_sp<GrGLProgram> fProgram;
29 };
30 
ProgramCache(GrGLGpu * gpu)31 GrGLGpu::ProgramCache::ProgramCache(GrGLGpu* gpu)
32     : fMap(kMaxEntries)
33     , fGpu(gpu)
34 #ifdef PROGRAM_CACHE_STATS
35     , fTotalRequests(0)
36     , fCacheMisses(0)
37     , fHashMisses(0)
38 #endif
39 {}
40 
~ProgramCache()41 GrGLGpu::ProgramCache::~ProgramCache() {
42     // dump stats
43 #ifdef PROGRAM_CACHE_STATS
44     if (c_DisplayCache) {
45         SkDebugf("--- Program Cache ---\n");
46         SkDebugf("Total requests: %d\n", fTotalRequests);
47         SkDebugf("Cache misses: %d\n", fCacheMisses);
48         SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
49                                             100.f * fCacheMisses / fTotalRequests :
50                                             0.f);
51         int cacheHits = fTotalRequests - fCacheMisses;
52         SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
53         SkDebugf("---------------------\n");
54     }
55 #endif
56 }
57 
abandon()58 void GrGLGpu::ProgramCache::abandon() {
59 #ifdef PROGRAM_CACHE_STATS
60     fTotalRequests = 0;
61     fCacheMisses = 0;
62     fHashMisses = 0;
63 #endif
64 
65     fMap.foreach([](std::unique_ptr<Entry>* e) {
66         (*e)->fProgram->abandon();
67     });
68     fMap.reset();
69 }
70 
refProgram(GrGLGpu * gpu,GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPrimitiveProcessor & primProc,const GrTextureProxy * const primProcProxies[],const GrPipeline & pipeline,bool isPoints)71 GrGLProgram* GrGLGpu::ProgramCache::refProgram(GrGLGpu* gpu,
72                                                GrRenderTarget* renderTarget,
73                                                GrSurfaceOrigin origin,
74                                                const GrPrimitiveProcessor& primProc,
75                                                const GrTextureProxy* const primProcProxies[],
76                                                const GrPipeline& pipeline,
77                                                bool isPoints) {
78 #ifdef PROGRAM_CACHE_STATS
79     ++fTotalRequests;
80 #endif
81 
82     // Get GrGLProgramDesc
83     GrProgramDesc desc;
84     if (!GrProgramDesc::Build(&desc, renderTarget, primProc, isPoints, pipeline, gpu)) {
85         GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n");
86         return nullptr;
87     }
88     std::unique_ptr<Entry>* entry = fMap.find(desc);
89     if (!entry) {
90         // Didn't find an origin-independent version, check with the specific origin
91         desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin));
92         entry = fMap.find(desc);
93     }
94     if (!entry) {
95         // We have a cache miss
96 #ifdef PROGRAM_CACHE_STATS
97         ++fCacheMisses;
98 #endif
99         GrGLProgram* program = GrGLProgramBuilder::CreateProgram(renderTarget, origin,
100                                                                  primProc, primProcProxies,
101                                                                  pipeline, &desc, fGpu);
102         if (nullptr == program) {
103             return nullptr;
104         }
105         entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(sk_sp<GrGLProgram>(program))));
106     }
107 
108     return SkRef((*entry)->fProgram.get());
109 }
110