aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/gl/builders
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2017-11-01 15:45:43 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-02 13:07:41 +0000
commitd1b2eec0d0f95977b52669025cb25038618c0335 (patch)
tree6e3bae30a741d09fd1cddb6448276f98b5adadf1 /src/gpu/gl/builders
parentb693fbf0fac5978650b2677cae7647128ddb52ab (diff)
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 <bsalomon@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Diffstat (limited to 'src/gpu/gl/builders')
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp182
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.h15
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.cpp87
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.h13
4 files changed, 199 insertions, 98 deletions
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&);