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