1 /*
2  * Copyright 2014 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 "GrGLProgramBuilder.h"
9 
10 #include "GrAutoLocaleSetter.h"
11 #include "GrContext.h"
12 #include "GrContextPriv.h"
13 #include "GrCoordTransform.h"
14 #include "GrGLProgramBuilder.h"
15 #include "GrProgramDesc.h"
16 #include "GrShaderCaps.h"
17 #include "GrSwizzle.h"
18 #include "SkAutoMalloc.h"
19 #include "SkATrace.h"
20 #include "SkTraceEvent.h"
21 #include "gl/GrGLGpu.h"
22 #include "gl/GrGLProgram.h"
23 #include "gl/builders/GrGLShaderStringBuilder.h"
24 #include "glsl/GrGLSLFragmentProcessor.h"
25 #include "glsl/GrGLSLGeometryProcessor.h"
26 #include "glsl/GrGLSLProgramDataManager.h"
27 #include "glsl/GrGLSLXferProcessor.h"
28 
29 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
30 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
31 
CreateProgram(GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPrimitiveProcessor & primProc,const GrTextureProxy * const primProcProxies[],const GrPipeline & pipeline,GrProgramDesc * desc,GrGLGpu * gpu)32 GrGLProgram* GrGLProgramBuilder::CreateProgram(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
33                                                const GrPrimitiveProcessor& primProc,
34                                                const GrTextureProxy* const primProcProxies[],
35                                                const GrPipeline& pipeline,
36                                                GrProgramDesc* desc,
37                                                GrGLGpu* gpu) {
38     SkASSERT(!pipeline.isBad());
39 
40     ATRACE_ANDROID_FRAMEWORK("Shader Compile");
41     GrAutoLocaleSetter als("C");
42 
43     // create a builder.  This will be handed off to effects so they can use it to add
44     // uniforms, varyings, textures, etc
45     GrGLProgramBuilder builder(gpu, renderTarget, origin,
46                                pipeline, primProc, primProcProxies, desc);
47 
48     auto persistentCache = gpu->getContext()->contextPriv().getPersistentCache();
49     if (persistentCache) {
50         sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
51         builder.fCached = persistentCache->load(*key);
52         // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
53         // doing necessary setup in addition to generating the SkSL code. Currently we are only able
54         // to skip the SkSL->GLSL step on a cache hit.
55     }
56     if (!builder.emitAndInstallProcs()) {
57         return nullptr;
58     }
59     return builder.finalize();
60 }
61 
62 /////////////////////////////////////////////////////////////////////////////
63 
GrGLProgramBuilder(GrGLGpu * gpu,GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,const GrTextureProxy * const primProcProxies[],GrProgramDesc * desc)64 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
65                                        GrRenderTarget* renderTarget,
66                                        GrSurfaceOrigin origin,
67                                        const GrPipeline& pipeline,
68                                        const GrPrimitiveProcessor& primProc,
69                                        const GrTextureProxy* const primProcProxies[],
70                                        GrProgramDesc* desc)
71         : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
72         , fGpu(gpu)
73         , fVaryingHandler(this)
74         , fUniformHandler(this)
75         , fVertexAttributeCnt(0)
76         , fInstanceAttributeCnt(0)
77         , fVertexStride(0)
78         , fInstanceStride(0) {}
79 
caps() const80 const GrCaps* GrGLProgramBuilder::caps() const {
81     return fGpu->caps();
82 }
83 
compileAndAttachShaders(const char * glsl,int length,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds,const SkSL::Program::Settings & settings,const SkSL::Program::Inputs & inputs)84 bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl,
85                                                  int length,
86                                                  GrGLuint programId,
87                                                  GrGLenum type,
88                                                  SkTDArray<GrGLuint>* shaderIds,
89                                                  const SkSL::Program::Settings& settings,
90                                                  const SkSL::Program::Inputs& inputs) {
91     GrGLGpu* gpu = this->gpu();
92     GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
93                                                    programId,
94                                                    type,
95                                                    glsl,
96                                                    length,
97                                                    gpu->stats(),
98                                                    settings);
99     if (!shaderId) {
100         return false;
101     }
102 
103     *shaderIds->append() = shaderId;
104     if (inputs.fFlipY) {
105         GrProgramDesc* d = this->desc();
106         d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(this->origin()));
107     }
108 
109     return true;
110 }
111 
compileAndAttachShaders(GrGLSLShaderBuilder & shader,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds,const SkSL::Program::Settings & settings,SkSL::Program::Inputs * outInputs)112 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
113                                                  GrGLuint programId,
114                                                  GrGLenum type,
115                                                  SkTDArray<GrGLuint>* shaderIds,
116                                                  const SkSL::Program::Settings& settings,
117                                                  SkSL::Program::Inputs* outInputs) {
118     SkSL::String glsl;
119     std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(gpu()->glContext(), type,
120                                                  shader.fCompilerStrings.begin(),
121                                                  shader.fCompilerStringLengths.begin(),
122                                                  shader.fCompilerStrings.count(),
123                                                  settings,
124                                                  &glsl);
125     *outInputs = program->fInputs;
126     return this->compileAndAttachShaders(glsl.c_str(),
127                                          glsl.size(),
128                                          programId,
129                                          type,
130                                          shaderIds,
131                                          settings,
132                                          *outInputs);
133 }
134 
computeCountsAndStrides(GrGLuint programID,const GrPrimitiveProcessor & primProc,bool bindAttribLocations)135 void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
136                                                  const GrPrimitiveProcessor& primProc,
137                                                  bool bindAttribLocations) {
138     fVertexAttributeCnt = primProc.numVertexAttributes();
139     fInstanceAttributeCnt = primProc.numInstanceAttributes();
140     fAttributes.reset(
141             new GrGLProgram::Attribute[fVertexAttributeCnt + fInstanceAttributeCnt]);
142     auto addAttr = [&](int i, const auto& a, size_t* stride) {
143         fAttributes[i].fCPUType = a.cpuType();
144         fAttributes[i].fGPUType = a.gpuType();
145         fAttributes[i].fOffset = *stride;
146         *stride += a.sizeAlign4();
147         fAttributes[i].fLocation = i;
148         if (bindAttribLocations) {
149             GL_CALL(BindAttribLocation(programID, i, a.name()));
150         }
151     };
152     fVertexStride = 0;
153     int i = 0;
154     for (const auto& attr : primProc.vertexAttributes()) {
155         addAttr(i++, attr, &fVertexStride);
156     }
157     SkASSERT(fVertexStride == primProc.vertexStride());
158     fInstanceStride = 0;
159     for (const auto& attr : primProc.instanceAttributes()) {
160         addAttr(i++, attr, &fInstanceStride);
161     }
162     SkASSERT(fInstanceStride == primProc.instanceStride());
163 }
164 
addInputVars(const SkSL::Program::Inputs & inputs)165 void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
166     if (inputs.fRTWidth) {
167         this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
168     }
169     if (inputs.fRTHeight) {
170         this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
171     }
172 }
173 
storeShaderInCache(const SkSL::Program::Inputs & inputs,GrGLuint programID,const SkSL::String & glsl)174 void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
175                                             const SkSL::String& glsl) {
176     if (!this->gpu()->getContext()->contextPriv().getPersistentCache()) {
177         return;
178     }
179     sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
180     if (fGpu->glCaps().programBinarySupport()) {
181         // binary cache
182         GrGLsizei length = 0;
183         GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
184         if (length > 0) {
185             GrGLenum binaryFormat;
186             std::unique_ptr<char[]> binary(new char[length]);
187             GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
188             size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length;
189             std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]);
190             size_t offset = 0;
191             memcpy(data.get() + offset, &inputs, sizeof(inputs));
192             offset += sizeof(inputs);
193             memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat));
194             offset += sizeof(binaryFormat);
195             memcpy(data.get() + offset, binary.get(), length);
196             this->gpu()->getContext()->contextPriv().getPersistentCache()->store(
197                                             *key, *SkData::MakeWithoutCopy(data.get(), dataLength));
198         }
199     } else {
200         // source cache
201         size_t dataLength = sizeof(inputs) + glsl.length();
202         std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]);
203         size_t offset = 0;
204         memcpy(data.get() + offset, &inputs, sizeof(inputs));
205         offset += sizeof(inputs);
206         memcpy(data.get() + offset, glsl.data(), glsl.length());
207         this->gpu()->getContext()->contextPriv().getPersistentCache()->store(
208                                             *key, *SkData::MakeWithoutCopy(data.get(), dataLength));
209     }
210 }
211 
finalize()212 GrGLProgram* GrGLProgramBuilder::finalize() {
213     TRACE_EVENT0("skia", TRACE_FUNC);
214 
215     // verify we can get a program id
216     GrGLuint programID;
217     GL_CALL_RET(programID, CreateProgram());
218     if (0 == programID) {
219         return nullptr;
220     }
221 
222     if (this->gpu()->glCaps().programBinarySupport() &&
223         this->gpu()->getContext()->contextPriv().getPersistentCache()) {
224         GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
225     }
226 
227     this->finalizeShaders();
228 
229     // compile shaders and bind attributes / uniforms
230     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
231     SkSL::Program::Settings settings;
232     settings.fCaps = this->gpu()->glCaps().shaderCaps();
233     settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
234     settings.fSharpenTextures = this->gpu()->getContext()->contextPriv().sharpenMipmappedTextures();
235     settings.fFragColorIsInOut = this->fragColorIsInOut();
236 
237     SkSL::Program::Inputs inputs;
238     SkTDArray<GrGLuint> shadersToDelete;
239     // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
240     bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
241 #ifdef SK_DEBUG
242     checkLinked = true;
243 #endif
244     bool cached = fCached.get() != nullptr;
245     SkSL::String glsl;
246     if (cached) {
247         const uint8_t* bytes = fCached->bytes();
248         size_t offset = 0;
249         memcpy(&inputs, bytes + offset, sizeof(inputs));
250         offset += sizeof(inputs);
251         if (fGpu->glCaps().programBinarySupport()) {
252             // binary cache hit, just hand the binary to GL
253             int binaryFormat;
254             memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat));
255             offset += sizeof(binaryFormat);
256             GrGLClearErr(this->gpu()->glInterface());
257             GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
258                                   ProgramBinary(programID, binaryFormat, (void*) (bytes + offset),
259                                                 fCached->size() - offset));
260             if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
261                 if (checkLinked) {
262                     cached = this->checkLinkStatus(programID);
263                 }
264                 if (cached) {
265                     this->addInputVars(inputs);
266                     this->computeCountsAndStrides(programID, primProc, false);
267                 }
268             } else {
269                 cached = false;
270             }
271         } else {
272             // source cache hit, we don't need to compile the SkSL->GLSL
273             glsl = SkSL::String(((const char*) bytes) + offset, fCached->size() - offset);
274         }
275     }
276     if (!cached || !fGpu->glCaps().programBinarySupport()) {
277         // either a cache miss, or we can't store binaries in the cache
278         if (glsl == "" || true) {
279             // don't have cached GLSL, need to compile SkSL->GLSL
280             if (fFS.fForceHighPrecision) {
281                 settings.fForceHighPrecision = true;
282             }
283             std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
284                                                              GR_GL_FRAGMENT_SHADER,
285                                                              fFS.fCompilerStrings.begin(),
286                                                              fFS.fCompilerStringLengths.begin(),
287                                                              fFS.fCompilerStrings.count(),
288                                                              settings,
289                                                              &glsl);
290             if (!fs) {
291                 this->cleanupProgram(programID, shadersToDelete);
292                 return nullptr;
293             }
294             inputs = fs->fInputs;
295         } else {
296             // we've pulled GLSL and inputs from the cache, but still need to do some setup
297             this->addInputVars(inputs);
298             this->computeCountsAndStrides(programID, primProc, false);
299         }
300         this->addInputVars(inputs);
301         if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
302                                            GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings,
303                                            inputs)) {
304             this->cleanupProgram(programID, shadersToDelete);
305             return nullptr;
306         }
307 
308         std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
309                                                          GR_GL_VERTEX_SHADER,
310                                                          fVS.fCompilerStrings.begin(),
311                                                          fVS.fCompilerStringLengths.begin(),
312                                                          fVS.fCompilerStrings.count(),
313                                                          settings,
314                                                          &glsl);
315         if (!vs || !this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
316                                                   GR_GL_VERTEX_SHADER, &shadersToDelete, settings,
317                                                   inputs)) {
318             this->cleanupProgram(programID, shadersToDelete);
319             return nullptr;
320         }
321 
322         // NVPR actually requires a vertex shader to compile
323         bool useNvpr = primProc.isPathRendering();
324         if (!useNvpr) {
325             this->computeCountsAndStrides(programID, primProc, true);
326         }
327 
328         if (primProc.willUseGeoShader()) {
329             std::unique_ptr<SkSL::Program> gs;
330             gs = GrSkSLtoGLSL(gpu()->glContext(),
331                               GR_GL_GEOMETRY_SHADER,
332                               fGS.fCompilerStrings.begin(),
333                               fGS.fCompilerStringLengths.begin(),
334                               fGS.fCompilerStrings.count(),
335                               settings,
336                               &glsl);
337             if (!gs || !this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
338                                                       GR_GL_GEOMETRY_SHADER, &shadersToDelete,
339                                                       settings, inputs)) {
340                 this->cleanupProgram(programID, shadersToDelete);
341                 return nullptr;
342             }
343         }
344         this->bindProgramResourceLocations(programID);
345 
346         GL_CALL(LinkProgram(programID));
347         if (checkLinked) {
348             if (!this->checkLinkStatus(programID)) {
349                 GL_CALL(DeleteProgram(programID));
350                 SkDebugf("VS:\n");
351                 GrGLPrintShader(fGpu->glContext(),
352                                 GR_GL_VERTEX_SHADER,
353                                 fVS.fCompilerStrings.begin(),
354                                 fVS.fCompilerStringLengths.begin(),
355                                 fVS.fCompilerStrings.count(),
356                                 settings);
357                 if (primProc.willUseGeoShader()) {
358                     SkDebugf("\nGS:\n");
359                     GrGLPrintShader(fGpu->glContext(),
360                                     GR_GL_GEOMETRY_SHADER,
361                                     fGS.fCompilerStrings.begin(),
362                                     fGS.fCompilerStringLengths.begin(),
363                                     fGS.fCompilerStrings.count(), settings);
364                 }
365                 SkDebugf("\nFS:\n");
366                 GrGLPrintShader(fGpu->glContext(),
367                                 GR_GL_FRAGMENT_SHADER,
368                                 fFS.fCompilerStrings.begin(),
369                                 fFS.fCompilerStringLengths.begin(),
370                                 fFS.fCompilerStrings.count(),
371                                 settings);
372                 return nullptr;
373             }
374         }
375     }
376     this->resolveProgramResourceLocations(programID);
377 
378     this->cleanupShaders(shadersToDelete);
379     if (!cached) {
380         this->storeShaderInCache(inputs, programID, glsl);
381     }
382     return this->createProgram(programID);
383 }
384 
bindProgramResourceLocations(GrGLuint programID)385 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
386     fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
387 
388     const GrGLCaps& caps = this->gpu()->glCaps();
389     if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
390         GL_CALL(BindFragDataLocation(programID, 0,
391                                      GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
392     }
393     if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
394         GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
395                                   GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
396     }
397 
398     // handle NVPR separable varyings
399     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
400         !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
401         return;
402     }
403     int count = fVaryingHandler.fPathProcVaryingInfos.count();
404     for (int i = 0; i < count; ++i) {
405         GL_CALL(BindFragmentInputLocation(programID, i,
406                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
407         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
408     }
409 }
410 
checkLinkStatus(GrGLuint programID)411 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
412     GrGLint linked = GR_GL_INIT_ZERO;
413     GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
414     if (!linked) {
415         SkDebugf("Program linking failed.\n");
416         GrGLint infoLen = GR_GL_INIT_ZERO;
417         GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
418         SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
419         if (infoLen > 0) {
420             // retrieve length even though we don't need it to workaround
421             // bug in chrome cmd buffer param validation.
422             GrGLsizei length = GR_GL_INIT_ZERO;
423             GL_CALL(GetProgramInfoLog(programID,
424                                       infoLen+1,
425                                       &length,
426                                       (char*)log.get()));
427             SkDebugf("%s", (char*)log.get());
428         }
429     }
430     return SkToBool(linked);
431 }
432 
resolveProgramResourceLocations(GrGLuint programID)433 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
434     fUniformHandler.getUniformLocations(programID, fGpu->glCaps());
435 
436     // handle NVPR separable varyings
437     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
438         fGpu->glPathRendering()->shouldBindFragmentInputs()) {
439         return;
440     }
441     int count = fVaryingHandler.fPathProcVaryingInfos.count();
442     for (int i = 0; i < count; ++i) {
443         GrGLint location;
444         GL_CALL_RET(location, GetProgramResourceLocation(
445                                        programID,
446                                        GR_GL_FRAGMENT_INPUT,
447                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
448         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
449     }
450 }
451 
cleanupProgram(GrGLuint programID,const SkTDArray<GrGLuint> & shaderIDs)452 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
453     GL_CALL(DeleteProgram(programID));
454     this->cleanupShaders(shaderIDs);
455 }
cleanupShaders(const SkTDArray<GrGLuint> & shaderIDs)456 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
457     for (int i = 0; i < shaderIDs.count(); ++i) {
458         GL_CALL(DeleteShader(shaderIDs[i]));
459     }
460 }
461 
createProgram(GrGLuint programID)462 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
463     return new GrGLProgram(fGpu,
464                            fUniformHandles,
465                            programID,
466                            fUniformHandler.fUniforms,
467                            fUniformHandler.fSamplers,
468                            fVaryingHandler.fPathProcVaryingInfos,
469                            std::move(fGeometryProcessor),
470                            std::move(fXferProcessor),
471                            std::move(fFragmentProcessors),
472                            fFragmentProcessorCnt,
473                            std::move(fAttributes),
474                            fVertexAttributeCnt,
475                            fInstanceAttributeCnt,
476                            fVertexStride,
477                            fInstanceStride);
478 }
479