When precompiling SkSL, avoid the need to re-link

Adds metadata to the SkSL blobs about attributes (and other resources)
so that we can do all necessary work during precompile.

Change-Id: I1846c6c96946d5a43a48112d062853717a6571a0
Bug: skia:9402
Bug: b/140174804
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/243739
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 38c15ff..c521c31 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -163,7 +163,7 @@
 
 void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
                                             const SkSL::String shaders[], bool isSkSL,
-                                            const SkSL::Program::Settings& settings) {
+                                            SkSL::Program::Settings* settings) {
     if (!this->gpu()->getContext()->priv().getPersistentCache()) {
         return;
     }
@@ -188,9 +188,20 @@
             this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
         }
     } else {
-        // source cache
+        // source cache, plus metadata to allow for a complete precompile
+        GrPersistentCacheUtils::ShaderMetadata meta;
+        meta.fSettings = settings;
+        meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
+        meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
+        for (const auto& attr : this->primitiveProcessor().vertexAttributes()) {
+            meta.fAttributeNames.emplace_back(attr.name());
+        }
+        for (const auto& attr : this->primitiveProcessor().instanceAttributes()) {
+            meta.fAttributeNames.emplace_back(attr.name());
+        }
+
         auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
-                                                              shaders, &inputs, 1, &settings);
+                                                              shaders, &inputs, 1, &meta);
         this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
     }
 }
@@ -247,12 +258,8 @@
     if (precompiledProgram) {
         // This is very similar to when we get program binaries. We even set that flag, as it's
         // used to prevent other compile work later, and to force re-querying uniform locations.
-        // We couldn't bind attribute or program resource locations during the pre-compile, so do
-        // that now. Those APIs don't take effect until the next link, so re-link the program.
         this->addInputVars(precompiledProgram->fInputs);
-        this->computeCountsAndStrides(programID, primProc, true);
-        this->bindProgramResourceLocations(programID);
-        GL_CALL(LinkProgram(programID));
+        this->computeCountsAndStrides(programID, primProc, false);
         usedProgramBinaries = true;
     } else if (cached) {
         SkReader32 reader(fCached->data(), fCached->size());
@@ -416,7 +423,7 @@
             }
             isSkSL = true;
         }
-        this->storeShaderInCache(inputs, programID, glsl, isSkSL, settings);
+        this->storeShaderInCache(inputs, programID, glsl, isSkSL, &settings);
     }
     return this->createProgram(programID);
 }
@@ -540,12 +547,15 @@
     SkTDArray<GrGLuint> shadersToDelete;
 
     SkSL::Program::Settings settings;
-    settings.fCaps = gpu->glCaps().shaderCaps();
+    const GrGLCaps& caps = gpu->glCaps();
+    settings.fCaps = caps.shaderCaps();
     settings.fSharpenTextures = gpu->getContext()->priv().options().fSharpenMipmappedTextures;
+    GrPersistentCacheUtils::ShaderMetadata meta;
+    meta.fSettings = &settings;
 
     SkSL::String shaders[kGrShaderTypeCount];
     SkSL::Program::Inputs inputs;
-    GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &settings);
+    GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta);
 
     auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
         SkSL::String glsl;
@@ -577,6 +587,20 @@
         return false;
     }
 
+    for (int i = 0; i < meta.fAttributeNames.count(); ++i) {
+        GR_GL_CALL(gpu->glInterface(), BindAttribLocation(programID, i,
+                                                          meta.fAttributeNames[i].c_str()));
+    }
+
+    if (meta.fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
+        GR_GL_CALL(gpu->glInterface(), BindFragDataLocation(programID, 0,
+                GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
+    }
+    if (meta.fHasSecondaryColorOutput && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
+        GR_GL_CALL(gpu->glInterface(), BindFragDataLocationIndexed(programID, 0, 1,
+                GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
+    }
+
     GR_GL_CALL(gpu->glInterface(), LinkProgram(programID));
     GrGLint linked = GR_GL_INIT_ZERO;
     GR_GL_CALL(gpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));