From d1b2eec0d0f95977b52669025cb25038618c0335 Mon Sep 17 00:00:00 2001 From: Ethan Nicholas Date: Wed, 1 Nov 2017 15:45:43 -0400 Subject: [PATCH] API to cache shader binaries between runs of Skia. This CL does not include an actual implementation of said cache. Stan is working on the cache implementation on the Android side of things. Bug: skia: Change-Id: Iabe4f19b2dbacaaa1ead8bb3fa68d88c687b9a84 Reviewed-on: https://skia-review.googlesource.com/54780 Reviewed-by: Brian Salomon Commit-Queue: Ethan Nicholas --- include/gpu/GrContext.h | 6 +- include/gpu/GrContextOptions.h | 25 +++ include/gpu/gl/GrGLFunctions.h | 3 + include/gpu/gl/GrGLInterface.h | 7 +- src/gpu/GrContext.cpp | 2 + src/gpu/gl/GrGLAssembleInterface.cpp | 12 ++ src/gpu/gl/GrGLCaps.cpp | 8 + src/gpu/gl/GrGLCaps.h | 5 + src/gpu/gl/GrGLCreateNullInterface.cpp | 3 +- src/gpu/gl/GrGLDefines.h | 4 + src/gpu/gl/GrGLGpu.cpp | 69 ++++--- src/gpu/gl/GrGLInterface.cpp | 9 + src/gpu/gl/GrGLTestInterface.cpp | 3 + src/gpu/gl/GrGLTestInterface.h | 3 + src/gpu/gl/builders/GrGLProgramBuilder.cpp | 190 +++++++++++++----- src/gpu/gl/builders/GrGLProgramBuilder.h | 15 +- .../gl/builders/GrGLShaderStringBuilder.cpp | 87 ++++---- src/gpu/gl/builders/GrGLShaderStringBuilder.h | 13 +- tools/gpu/gl/debug/DebugGLTestContext.cpp | 3 +- 19 files changed, 330 insertions(+), 137 deletions(-) diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index e5f568c9e9..41d00a6802 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -15,10 +15,10 @@ #include "SkTypes.h" #include "../private/GrAuditTrail.h" #include "../private/GrSingleOwner.h" +#include "GrContextOptions.h" class GrAtlasGlyphCache; class GrBackendSemaphore; -struct GrContextOptions; class GrContextPriv; class GrContextThreadSafeProxy; class GrDrawingManager; @@ -334,6 +334,8 @@ public: GrAuditTrail* getAuditTrail() { return &fAuditTrail; } + GrContextOptions::PersistentCache* getPersistentCache() { return fPersistentCache; } + /** This is only useful for debug purposes */ SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fSingleOwner; } ) @@ -379,6 +381,8 @@ private: GrBackend fBackend; + GrContextOptions::PersistentCache* fPersistentCache; + // TODO: have the GrClipStackClip use renderTargetContexts and rm this friending friend class GrContextPriv; diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h index 894813b5cc..7aa85e0ed3 100644 --- a/include/gpu/GrContextOptions.h +++ b/include/gpu/GrContextOptions.h @@ -8,10 +8,13 @@ #ifndef GrContextOptions_DEFINED #define GrContextOptions_DEFINED +#include "SkData.h" #include "SkTypes.h" #include "GrTypes.h" #include "../private/GrTypesPriv.h" +#include + class SkExecutor; struct GrContextOptions { @@ -26,6 +29,23 @@ struct GrContextOptions { kDefault }; + /** + * Abstract class which stores Skia data in a cache that persists between sessions. Currently, + * Skia stores compiled shader binaries (only when glProgramBinary / glGetProgramBinary are + * supported) when provided a persistent cache, but this may extend to other data in the future. + */ + class PersistentCache { + public: + virtual ~PersistentCache() {} + + /** + * Returns the data for the key if it exists in the cache, otherwise returns null. + */ + virtual sk_sp load(const SkData& key) = 0; + + virtual void store(const SkData& key, const SkData& data) = 0; + }; + GrContextOptions() {} // Suppress prints for the GrContext. @@ -105,6 +125,11 @@ struct GrContextOptions { */ Enable fUseDrawInsteadOfGLClear = Enable::kDefault; + /** + * Cache in which to store compiled shader binaries between runs. + */ + PersistentCache* fPersistentCache = nullptr; + #if GR_TEST_UTILS /** * Private options that are only meant for testing within Skia's tools. diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h index 90c3de1caa..3ccfb62a4d 100644 --- a/include/gpu/gl/GrGLFunctions.h +++ b/include/gpu/gl/GrGLFunctions.h @@ -91,6 +91,7 @@ typedef GrGLenum (* GrGLGetErrorProc)(); typedef GrGLvoid (* GrGLGetFramebufferAttachmentParameterivProc)(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params); typedef GrGLvoid (* GrGLGetIntegervProc)(GrGLenum pname, GrGLint* params); typedef GrGLvoid (* GrGLGetMultisamplefvProc)(GrGLenum pname, GrGLuint index, GrGLfloat* val); +typedef GrGLvoid (* GrGLGetProgramBinaryProc)(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, GrGLenum *binaryFormat, void *binary); typedef GrGLvoid (* GrGLGetProgramInfoLogProc)(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog); typedef GrGLvoid (* GrGLGetProgramivProc)(GrGLuint program, GrGLenum pname, GrGLint* params); typedef GrGLvoid (* GrGLGetQueryivProc)(GrGLenum GLtarget, GrGLenum pname, GrGLint *params); @@ -125,6 +126,8 @@ typedef GrGLvoid* (* GrGLMemoryBarrierByRegionProc)(GrGLbitfield barriers); typedef GrGLvoid (* GrGLPixelStoreiProc)(GrGLenum pname, GrGLint param); typedef GrGLvoid (* GrGLPolygonModeProc)(GrGLenum face, GrGLenum mode); typedef GrGLvoid (* GrGLPopGroupMarkerProc)(); +typedef GrGLvoid (* GrGLProgramBinaryProc)(GrGLuint program, GrGLenum binaryFormat, void *binary, GrGLsizei length); +typedef GrGLvoid (* GrGLProgramParameteriProc)(GrGLuint program, GrGLenum pname, GrGLint value); typedef GrGLvoid (* GrGLPushGroupMarkerProc)(GrGLsizei length, const char* marker); typedef GrGLvoid (* GrGLQueryCounterProc)(GrGLuint id, GrGLenum target); typedef GrGLvoid (* GrGLRasterSamplesProc)(GrGLuint samples, GrGLboolean fixedsamplelocations); diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index f1785326fb..e752c2d6e8 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -177,13 +177,14 @@ public: GrGLFunction fGetFramebufferAttachmentParameteriv; GrGLFunction fGetIntegerv; GrGLFunction fGetMultisamplefv; + GrGLFunction fGetProgramBinary; + GrGLFunction fGetProgramInfoLog; + GrGLFunction fGetProgramiv; GrGLFunction fGetQueryObjecti64v; GrGLFunction fGetQueryObjectiv; GrGLFunction fGetQueryObjectui64v; GrGLFunction fGetQueryObjectuiv; GrGLFunction fGetQueryiv; - GrGLFunction fGetProgramInfoLog; - GrGLFunction fGetProgramiv; GrGLFunction fGetRenderbufferParameteriv; GrGLFunction fGetShaderInfoLog; GrGLFunction fGetShaderiv; @@ -202,6 +203,8 @@ public: GrGLFunction fIsTexture; GrGLFunction fLineWidth; GrGLFunction fLinkProgram; + GrGLFunction fProgramBinary; + GrGLFunction fProgramParameteri; GrGLFunction fMapBuffer; GrGLFunction fMapBufferRange; GrGLFunction fMapBufferSubData; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 2d9f0115e3..2146858f79 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -213,6 +213,8 @@ bool GrContext::init(const GrContextOptions& options) { fTaskGroup = skstd::make_unique(*options.fExecutor); } + fPersistentCache = options.fPersistentCache; + return true; } diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index d33a8b6cb1..b7698f1473 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -535,6 +535,12 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_PROC(GetInternalformativ); } + if (glVer >= GR_GL_VER(4, 1)) { + GET_PROC(GetProgramBinary); + GET_PROC(ProgramBinary); + GET_PROC(ProgramParameteri); + } + interface->fStandard = kGL_GrGLStandard; interface->fExtensions.swap(&extensions); @@ -977,6 +983,12 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { GET_PROC(GetInternalformativ); } + if (version >= GR_GL_VER(3, 0)) { + GET_PROC(GetProgramBinary); + GET_PROC(ProgramBinary); + GET_PROC(ProgramParameteri); + } + interface->fStandard = kGLES_GrGLStandard; interface->fExtensions.swap(&extensions); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 4ba504c4c9..9a454ef2b7 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -718,6 +718,14 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fDrawArraysBaseVertexIsBroken = true; } + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 1)) { + fProgramBinarySupport = true; + } + } else if (version >= GR_GL_VER(3, 0)) { + fProgramBinarySupport = true; + } + // Requires fTextureRedSupport, fTextureSwizzleSupport, msaa support, ES compatibility have // already been detected. this->initConfigTable(contextOptions, ctxInfo, gli, shaderCaps); diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index e9c325313a..2c82c4c021 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -414,6 +414,10 @@ public: bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, bool* rectsMustMatch, bool* disallowSubrect) const override; + bool programBinarySupport() const { + return fProgramBinarySupport; + } + private: enum ExternalFormatUsage { kTexImage_ExternalFormatUsage, @@ -490,6 +494,7 @@ private: bool fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO : 1; bool fUseDrawInsteadOfAllRenderTargetWrites : 1; bool fRequiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines : 1; + bool fProgramBinarySupport : 1; uint32_t fBlitFramebufferFlags; int fMaxInstancesPerDrawArraysWithoutCrashing; diff --git a/src/gpu/gl/GrGLCreateNullInterface.cpp b/src/gpu/gl/GrGLCreateNullInterface.cpp index e130247862..3b8b1fec04 100644 --- a/src/gpu/gl/GrGLCreateNullInterface.cpp +++ b/src/gpu/gl/GrGLCreateNullInterface.cpp @@ -789,7 +789,8 @@ private: case GR_GL_COMPILE_STATUS: *params = GR_GL_TRUE; break; - case GR_GL_INFO_LOG_LENGTH: + case GR_GL_INFO_LOG_LENGTH: // fallthru + case GL_PROGRAM_BINARY_LENGTH: *params = 0; break; // we don't expect any other pnames diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h index b62c26bcc2..db6abd482f 100644 --- a/src/gpu/gl/GrGLDefines.h +++ b/src/gpu/gl/GrGLDefines.h @@ -1079,4 +1079,8 @@ #define GR_EGL_NONE 0x3038 #define GR_EGL_NO_IMAGE ((GrEGLImage)0) +/* Programs */ +#define GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 + #endif diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index d3bd6e3cd0..6b194f98f7 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -3570,18 +3570,21 @@ bool GrGLGpu::createCopyProgram(GrTexture* srcTex) { length = SkToInt(vshaderTxt.size()); SkSL::Program::Settings settings; settings.fCaps = shaderCaps; - SkSL::Program::Inputs inputs; + SkSL::String glsl; + std::unique_ptr program = GrSkSLtoGLSL(*fGLContext, GR_GL_VERTEX_SHADER, + &str, &length, 1, settings, &glsl); GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram, - GR_GL_VERTEX_SHADER, &str, &length, 1, - &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_VERTEX_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); + program = GrSkSLtoGLSL(*fGLContext, GR_GL_FRAGMENT_SHADER, &str, &length, 1, settings, &glsl); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, - &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_FRAGMENT_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram)); @@ -3726,18 +3729,21 @@ bool GrGLGpu::createMipmapProgram(int progIdx) { length = SkToInt(vshaderTxt.size()); SkSL::Program::Settings settings; settings.fCaps = shaderCaps; - SkSL::Program::Inputs inputs; + SkSL::String glsl; + std::unique_ptr program = GrSkSLtoGLSL(*fGLContext, GR_GL_VERTEX_SHADER, + &str, &length, 1, settings, &glsl); GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram, - GR_GL_VERTEX_SHADER, &str, &length, 1, - &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_VERTEX_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); + program = GrSkSLtoGLSL(*fGLContext, GR_GL_FRAGMENT_SHADER, &str, &length, 1, settings, &glsl); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, - &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_FRAGMENT_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram)); @@ -3798,18 +3804,21 @@ bool GrGLGpu::createStencilClipClearProgram() { length = SkToInt(vshaderTxt.size()); SkSL::Program::Settings settings; settings.fCaps = this->caps()->shaderCaps(); - SkSL::Program::Inputs inputs; - GrGLuint vshader = - GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, GR_GL_VERTEX_SHADER, - &str, &length, 1, &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + SkSL::String glsl; + std::unique_ptr program = GrSkSLtoGLSL(*fGLContext, GR_GL_VERTEX_SHADER, + &str, &length, 1, settings, &glsl); + GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, + GR_GL_VERTEX_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); - GrGLuint fshader = - GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, GR_GL_FRAGMENT_SHADER, - &str, &length, 1, &fStats, settings, &inputs); - SkASSERT(inputs.isEmpty()); + program = GrSkSLtoGLSL(*fGLContext, GR_GL_FRAGMENT_SHADER, &str, &length, 1, settings, &glsl); + GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, + GR_GL_FRAGMENT_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); + SkASSERT(program->fInputs.isEmpty()); GL_CALL(LinkProgram(fStencilClipClearProgram)); @@ -3910,18 +3919,18 @@ bool GrGLGpu::createClearColorProgram() { length = SkToInt(vshaderTxt.size()); SkSL::Program::Settings settings; settings.fCaps = this->caps()->shaderCaps(); - SkSL::Program::Inputs inputs; + SkSL::String glsl; + GrSkSLtoGLSL(*fGLContext, GR_GL_VERTEX_SHADER, &str, &length, 1, settings, &glsl); GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fClearColorProgram.fProgram, - GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats, - settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_VERTEX_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); str = fshaderTxt.c_str(); length = SkToInt(fshaderTxt.size()); + GrSkSLtoGLSL(*fGLContext, GR_GL_FRAGMENT_SHADER, &str, &length, 1, settings, &glsl); GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fClearColorProgram.fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats, - settings, &inputs); - SkASSERT(inputs.isEmpty()); + GR_GL_FRAGMENT_SHADER, glsl.c_str(), glsl.size(), + &fStats, settings); GL_CALL(LinkProgram(fClearColorProgram.fProgram)); diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index 81c4569519..8ce8af7098 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -819,5 +819,14 @@ bool GrGLInterface::validate() const { } } + if ((kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,1)) || + (kGLES_GrGLStandard == fStandard && glVer >= GR_GL_VER(3,0))) { + if (!fFunctions.fGetProgramBinary || + !fFunctions.fProgramBinary || + !fFunctions.fProgramParameteri) { + RETURN_FALSE_INTERFACE; + } + } + return true; } diff --git a/src/gpu/gl/GrGLTestInterface.cpp b/src/gpu/gl/GrGLTestInterface.cpp index d95fd09120..bceb947c58 100644 --- a/src/gpu/gl/GrGLTestInterface.cpp +++ b/src/gpu/gl/GrGLTestInterface.cpp @@ -326,4 +326,7 @@ GrGLTestInterface::GrGLTestInterface() { fFunctions.fPopDebugGroup = bind_to_member(this, &GrGLTestInterface::popDebugGroup); fFunctions.fObjectLabel = bind_to_member(this, &GrGLTestInterface::objectLabel); fFunctions.fGetInternalformativ = bind_to_member(this, &GrGLTestInterface::getInternalformativ); + fFunctions.fProgramBinary = bind_to_member(this, &GrGLTestInterface::programBinary); + fFunctions.fGetProgramBinary = bind_to_member(this, &GrGLTestInterface::getProgramBinary); + fFunctions.fProgramParameteri = bind_to_member(this, &GrGLTestInterface::programParameteri); } diff --git a/src/gpu/gl/GrGLTestInterface.h b/src/gpu/gl/GrGLTestInterface.h index 1ebf90b7cf..58b6f84c02 100644 --- a/src/gpu/gl/GrGLTestInterface.h +++ b/src/gpu/gl/GrGLTestInterface.h @@ -331,6 +331,9 @@ public: virtual GrGLvoid popDebugGroup() {} virtual GrGLvoid objectLabel(GrGLenum identifier, GrGLuint name, GrGLsizei length, const GrGLchar *label) {} virtual GrGLvoid getInternalformativ(GrGLenum target, GrGLenum internalformat, GrGLenum pname, GrGLsizei bufSize, GrGLint *params) {} + virtual GrGLvoid programBinary(GrGLuint program, GrGLenum binaryFormat, void *binary, GrGLsizei length) {} + virtual GrGLvoid getProgramBinary(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, GrGLenum *binaryFormat, void *binary) {} + virtual GrGLvoid programParameteri(GrGLuint program, GrGLenum pname, GrGLint value) {} protected: // This must be called by leaf class diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 31d20f0421..c9bc8f8910 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -41,11 +41,17 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline, // uniforms, varyings, textures, etc GrGLProgramBuilder builder(gpu, pipeline, primProc, desc); + if (gpu->getContext()->getPersistentCache() && gpu->glCaps().programBinarySupport()) { + sk_sp key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength()); + builder.fCached = gpu->getContext()->getPersistentCache()->load(*key); + // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's + // doing necessary setup in addition to generating the SkSL code. Currently we are only able + // to skip the SkSL->GLSL step on a cache hit. + } if (!builder.emitAndInstallProcs()) { builder.cleanupFragmentProcessors(); return nullptr; } - return builder.finalize(); } @@ -65,29 +71,27 @@ const GrCaps* GrGLProgramBuilder::caps() const { return fGpu->caps(); } -bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, +bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl, + int length, GrGLuint programId, GrGLenum type, SkTDArray* shaderIds, const SkSL::Program::Settings& settings, - SkSL::Program::Inputs* outInputs) { + const SkSL::Program::Inputs& inputs) { GrGLGpu* gpu = this->gpu(); GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId, type, - shader.fCompilerStrings.begin(), - shader.fCompilerStringLengths.begin(), - shader.fCompilerStrings.count(), + glsl, + length, gpu->stats(), - settings, - outInputs); - + settings); if (!shaderId) { return false; } *shaderIds->append() = shaderId; - if (outInputs->fFlipY) { + if (inputs.fFlipY) { GrProgramDesc* d = this->desc(); d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( this->pipeline().proxy()->origin())); @@ -97,6 +101,29 @@ bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, return true; } +bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, + GrGLuint programId, + GrGLenum type, + SkTDArray* shaderIds, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { + SkSL::String glsl; + std::unique_ptr program = GrSkSLtoGLSL(gpu()->glContext(), type, + shader.fCompilerStrings.begin(), + shader.fCompilerStringLengths.begin(), + shader.fCompilerStrings.count(), + settings, + &glsl); + *outInputs = program->fInputs; + return this->compileAndAttachShaders(glsl.c_str(), + glsl.size(), + programId, + type, + shaderIds, + settings, + *outInputs); +} + GrGLProgram* GrGLProgramBuilder::finalize() { TRACE_EVENT0("skia", TRACE_FUNC); @@ -108,54 +135,99 @@ GrGLProgram* GrGLProgramBuilder::finalize() { return nullptr; } + if (this->gpu()->getContext()->getPersistentCache()) { + GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE)); + } + this->finalizeShaders(); // compile shaders and bind attributes / uniforms + const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); SkSL::Program::Settings settings; settings.fCaps = this->gpu()->glCaps().shaderCaps(); settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin; SkSL::Program::Inputs inputs; SkTDArray shadersToDelete; - if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete, - settings, &inputs)) { - this->cleanupProgram(programID, shadersToDelete); - return nullptr; - } - - // NVPR actually requires a vertex shader to compile - const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); - bool useNvpr = primProc.isPathRendering(); - if (!useNvpr) { - int vaCount = primProc.numAttribs(); - for (int i = 0; i < vaCount; i++) { - GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); + bool cached = nullptr != fCached.get(); + if (cached) { + // cache hit, just hand the binary to GL + const uint8_t* bytes = fCached->bytes(); + size_t offset = 0; + memcpy(&inputs, bytes + offset, sizeof(inputs)); + offset += sizeof(inputs); + int binaryFormat; + memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat)); + offset += sizeof(binaryFormat); + GL_CALL(ProgramBinary(programID, binaryFormat, (void*) (bytes + offset), + fCached->size() - offset)); + } else { + // cache miss, compile shaders + if (fFS.fForceHighPrecision) { + settings.fForceHighPrecision = true; } + SkSL::String glsl; + std::unique_ptr fs = GrSkSLtoGLSL(gpu()->glContext(), + GR_GL_FRAGMENT_SHADER, + fFS.fCompilerStrings.begin(), + fFS.fCompilerStringLengths.begin(), + fFS.fCompilerStrings.count(), + settings, + &glsl); + inputs = fs->fInputs; + if (inputs.fRTHeight) { + this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); + } + if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, + GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings, + inputs)) { + this->cleanupProgram(programID, shadersToDelete); + return nullptr; + } + + std::unique_ptr vs = GrSkSLtoGLSL(gpu()->glContext(), + GR_GL_VERTEX_SHADER, + fVS.fCompilerStrings.begin(), + fVS.fCompilerStringLengths.begin(), + fVS.fCompilerStrings.count(), + settings, + &glsl); + if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, + GR_GL_VERTEX_SHADER, &shadersToDelete, settings, + inputs)) { + this->cleanupProgram(programID, shadersToDelete); + return nullptr; + } + + // NVPR actually requires a vertex shader to compile + bool useNvpr = primProc.isPathRendering(); + if (!useNvpr) { + int vaCount = primProc.numAttribs(); + for (int i = 0; i < vaCount; i++) { + GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); + } + } + + if (primProc.willUseGeoShader()) { + std::unique_ptr gs; + gs = GrSkSLtoGLSL(gpu()->glContext(), + GR_GL_GEOMETRY_SHADER, + fGS.fCompilerStrings.begin(), + fGS.fCompilerStringLengths.begin(), + fGS.fCompilerStrings.count(), + settings, + &glsl); + if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID, + GR_GL_GEOMETRY_SHADER, &shadersToDelete, settings, + inputs)) { + this->cleanupProgram(programID, shadersToDelete); + return nullptr; + } + + } + this->bindProgramResourceLocations(programID); + + GL_CALL(LinkProgram(programID)); } - - if (primProc.willUseGeoShader() && - !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete, - settings, &inputs)) { - this->cleanupProgram(programID, shadersToDelete); - return nullptr; - } - - if (fFS.fForceHighPrecision) { - settings.fForceHighPrecision = true; - } - if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete, - settings, &inputs)) { - this->cleanupProgram(programID, shadersToDelete); - return nullptr; - } - - if (inputs.fRTHeight) { - this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); - } - - this->bindProgramResourceLocations(programID); - - GL_CALL(LinkProgram(programID)); - // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver(); #ifdef SK_DEBUG @@ -184,7 +256,27 @@ GrGLProgram* GrGLProgramBuilder::finalize() { this->resolveProgramResourceLocations(programID); this->cleanupShaders(shadersToDelete); - + if (!cached && this->gpu()->getContext()->getPersistentCache() && + fGpu->glCaps().programBinarySupport()) { + // store shader in cache + sk_sp key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength()); + GrGLsizei length = 0; + GrGLenum binaryFormat; + GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length)); + std::unique_ptr binary(new char[length]); + GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get())); + size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length; + std::unique_ptr data((uint8_t*) malloc(dataLength)); + size_t offset = 0; + memcpy(data.get() + offset, &inputs, sizeof(inputs)); + offset += sizeof(inputs); + memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat)); + offset += sizeof(binaryFormat); + memcpy(data.get() + offset, binary.get(), length); + this->gpu()->getContext()->getPersistentCache()->store(*key, + *SkData::MakeWithoutCopy(data.get(), + dataLength)); + } return this->createProgram(programID); } diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index cfbb734155..54c91b448b 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -47,6 +47,14 @@ private: GrGLProgramBuilder(GrGLGpu*, const GrPipeline&, const GrPrimitiveProcessor&, GrProgramDesc*); + bool compileAndAttachShaders(const char* glsl, + int length, + GrGLuint programId, + GrGLenum type, + SkTDArray* shaderIds, + const SkSL::Program::Settings& settings, + const SkSL::Program::Inputs& inputs); + bool compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, GrGLenum type, @@ -67,11 +75,16 @@ private: const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; } - GrGLGpu* fGpu; GrGLVaryingHandler fVaryingHandler; GrGLUniformHandler fUniformHandler; + // shader pulled from cache. Data is organized as: + // SkSL::Program::Inputs inputs + // int binaryFormat + // (all remaining bytes) char[] binary + sk_sp fCached; + typedef GrGLSLProgramBuilder INHERITED; }; #endif diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp index f7eae42ca0..eb2d4644d0 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp @@ -32,24 +32,41 @@ static void print_source_lines_with_numbers(const char* source, } // Prints shaders one line at the time. This ensures they don't get truncated by the adb log. -static void print_shaders_line_by_line(const char** skslStrings, int* lengths, - int count, const SkSL::String& glsl, - std::function println = [](const char* ln) { - SkDebugf("%s\n", ln); - }) { +static void print_sksl_line_by_line(const char** skslStrings, int* lengths, int count, + std::function println = [](const char* ln) { + SkDebugf("%s\n", ln); + }) { SkSL::String sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false); println("SKSL:"); print_source_lines_with_numbers(sksl.c_str(), println); - if (0 != glsl.size()) { - println("GLSL:"); - print_source_lines_with_numbers(glsl.c_str(), println); - } } -std::unique_ptr translate_to_glsl(const GrGLContext& context, GrGLenum type, - const char** skslStrings, int* lengths, int count, - const SkSL::Program::Settings& settings, - SkSL::String* glsl) { +static void print_glsl_line_by_line(const SkSL::String& glsl, + std::function println = [](const char* ln) { + SkDebugf("%s\n", ln); + }) { + println("GLSL:"); + print_source_lines_with_numbers(glsl.c_str(), println); +} + +std::unique_ptr GrSkSLtoGLSL(const GrGLContext& context, GrGLenum type, + const char** skslStrings, int* lengths, int count, + const SkSL::Program::Settings& settings, + SkSL::String* glsl) { + // Trace event for shader preceding driver compilation + bool traceShader; + TRACE_EVENT_CATEGORY_GROUP_ENABLED("skia.gpu", &traceShader); + if (traceShader) { + SkString shaderDebugString; + print_sksl_line_by_line(skslStrings, lengths, count, [&](const char* ln) { + shaderDebugString.append(ln); + shaderDebugString.append("\n"); + }); + TRACE_EVENT_INSTANT1("skia.gpu", "skia_gpu::GLShader", + TRACE_EVENT_SCOPE_THREAD, "shader", + TRACE_STR_COPY(shaderDebugString.c_str())); + } + SkSL::String sksl; #ifdef SK_DEBUG sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false); @@ -69,7 +86,7 @@ std::unique_ptr translate_to_glsl(const GrGLContext& context, GrG program = compiler->convertProgram(programKind, sksl, settings); if (!program || !compiler->toGLSL(*program, glsl)) { SkDebugf("SKSL compilation error\n----------------------\n"); - print_shaders_line_by_line(skslStrings, lengths, count, *glsl); + print_sksl_line_by_line(skslStrings, lengths, count); SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str()); SkDEBUGFAIL("SKSL compilation failed!\n"); return nullptr; @@ -80,43 +97,19 @@ std::unique_ptr translate_to_glsl(const GrGLContext& context, GrG GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GrGLuint programId, GrGLenum type, - const char** skslStrings, - int* lengths, - int count, + const char* glsl, + int glslLength, GrGpu::Stats* stats, - const SkSL::Program::Settings& settings, - SkSL::Program::Inputs* outInputs) { + const SkSL::Program::Settings& settings) { const GrGLInterface* gli = glCtx.interface(); - SkSL::String glsl; - auto program = translate_to_glsl(glCtx, type, skslStrings, lengths, count, settings, &glsl); - if (!program) { - return 0; - } - // Specify GLSL source to the driver. GrGLuint shaderId; GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); if (0 == shaderId) { return 0; } - const char* glslChars = glsl.c_str(); - GrGLint glslLength = (GrGLint) glsl.size(); - GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength)); - - // Trace event for shader preceding driver compilation - bool traceShader; - TRACE_EVENT_CATEGORY_GROUP_ENABLED("skia.gpu", &traceShader); - if (traceShader) { - SkString shaderDebugString; - print_shaders_line_by_line(skslStrings, lengths, count, glsl, [&](const char* ln) { - shaderDebugString.append(ln); - shaderDebugString.append("\n"); - }); - TRACE_EVENT_INSTANT1("skia.gpu", "skia_gpu::GLShader", - TRACE_EVENT_SCOPE_THREAD, "shader", - TRACE_STR_COPY(shaderDebugString.c_str())); - } + GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glsl, &glslLength)); stats->incShaderCompilations(); GR_GL_CALL(gli, CompileShader(shaderId)); @@ -132,7 +125,7 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, if (!compiled) { SkDebugf("GLSL compilation error\n----------------------\n"); - print_shaders_line_by_line(skslStrings, lengths, count, glsl); + print_glsl_line_by_line(glsl); GrGLint infoLen = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen)); SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger @@ -157,7 +150,7 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break; } SkDebugf("---- %s shader ----------------------------------------------------\n", typeName); - print_shaders_line_by_line(skslStrings, lengths, count, glsl); + print_glsl_line_by_line(glsl); } // Attach the shader, but defer deletion until after we have linked the program. @@ -165,14 +158,14 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, // will immediately delete the shader object and free its memory even though it's // attached to a program, which then causes glLinkProgram to fail. GR_GL_CALL(gli, AttachShader(programId, shaderId)); - *outInputs = program->fInputs; return shaderId; } void GrGLPrintShader(const GrGLContext& context, GrGLenum type, const char** skslStrings, int* lengths, int count, const SkSL::Program::Settings& settings) { + print_sksl_line_by_line(skslStrings, lengths, count); SkSL::String glsl; - if (translate_to_glsl(context, type, skslStrings, lengths, count, settings, &glsl)) { - print_shaders_line_by_line(skslStrings, lengths, count, glsl); + if (GrSkSLtoGLSL(context, type, skslStrings, lengths, count, settings, &glsl)) { + print_glsl_line_by_line(glsl); } } diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.h b/src/gpu/gl/builders/GrGLShaderStringBuilder.h index 59dea35b8d..c693a390cc 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.h +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.h @@ -14,15 +14,18 @@ #include "SkSLGLSLCodeGenerator.h" #include "SkTypes.h" +std::unique_ptr GrSkSLtoGLSL(const GrGLContext& context, GrGLenum type, + const char** skslStrings, int* lengths, int count, + const SkSL::Program::Settings& settings, + SkSL::String* glsl); + GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GrGLuint programId, GrGLenum type, - const char** skslStrings, - int* lengths, - int count, + const char* glsl, + int glslLength, GrGpu::Stats*, - const SkSL::Program::Settings& settings, - SkSL::Program::Inputs* inputs); + const SkSL::Program::Settings& settings); void GrGLPrintShader(const GrGLContext&, GrGLenum type, const char** skslStrings, int* lengths, int count, const SkSL::Program::Settings&); diff --git a/tools/gpu/gl/debug/DebugGLTestContext.cpp b/tools/gpu/gl/debug/DebugGLTestContext.cpp index 3cecd07a0a..f16692e8e0 100644 --- a/tools/gpu/gl/debug/DebugGLTestContext.cpp +++ b/tools/gpu/gl/debug/DebugGLTestContext.cpp @@ -982,7 +982,8 @@ private: case GR_GL_COMPILE_STATUS: *params = GR_GL_TRUE; break; - case GR_GL_INFO_LOG_LENGTH: + case GR_GL_INFO_LOG_LENGTH: // fallthru + case GL_PROGRAM_BINARY_LENGTH: *params = 0; break; // we don't expect any other pnames