diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrContext.cpp | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLAssembleInterface.cpp | 12 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 8 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 5 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCreateNullInterface.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/GrGLDefines.h | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 69 | ||||
-rw-r--r-- | src/gpu/gl/GrGLInterface.cpp | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTestInterface.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTestInterface.h | 3 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.cpp | 182 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.h | 15 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLShaderStringBuilder.cpp | 87 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLShaderStringBuilder.h | 13 |
14 files changed, 286 insertions, 129 deletions
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<SkTaskGroup>(*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<SkSL::Program> 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<SkSL::Program> 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<SkSL::Program> 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<SkData> 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<GrGLuint>* 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<GrGLuint>* shaderIds, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { + SkSL::String glsl; + std::unique_ptr<SkSL::Program> 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<GrGLuint> 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<SkSL::Program> 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; } - } - - 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; - } + std::unique_ptr<SkSL::Program> 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; + } - if (inputs.fRTHeight) { - this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); - } + // 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)); + } + } - this->bindProgramResourceLocations(programID); + if (primProc.willUseGeoShader()) { + std::unique_ptr<SkSL::Program> 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; + } - GL_CALL(LinkProgram(programID)); + } + 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<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength()); + GrGLsizei length = 0; + GrGLenum binaryFormat; + GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length)); + std::unique_ptr<char> binary(new char[length]); + GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get())); + size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length; + std::unique_ptr<uint8_t> 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<GrGLuint>* 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<SkData> 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<void(const char*)> println = [](const char* ln) { - SkDebugf("%s\n", ln); - }) { +static void print_sksl_line_by_line(const char** skslStrings, int* lengths, int count, + std::function<void(const char*)> 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<SkSL::Program> 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<void(const char*)> println = [](const char* ln) { + SkDebugf("%s\n", ln); + }) { + println("GLSL:"); + print_source_lines_with_numbers(glsl.c_str(), println); +} + +std::unique_ptr<SkSL::Program> 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<SkSL::Program> 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<SkSL::Program> 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<SkSL::Program> 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&); |