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>
This commit is contained in:
Ethan Nicholas 2017-11-01 15:45:43 -04:00 committed by Skia Commit-Bot
parent b693fbf0fa
commit d1b2eec0d0
19 changed files with 330 additions and 137 deletions

View File

@ -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;

View File

@ -8,10 +8,13 @@
#ifndef GrContextOptions_DEFINED
#define GrContextOptions_DEFINED
#include "SkData.h"
#include "SkTypes.h"
#include "GrTypes.h"
#include "../private/GrTypesPriv.h"
#include <vector>
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<SkData> 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.

View File

@ -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);

View File

@ -177,13 +177,14 @@ public:
GrGLFunction<GrGLGetFramebufferAttachmentParameterivProc> fGetFramebufferAttachmentParameteriv;
GrGLFunction<GrGLGetIntegervProc> fGetIntegerv;
GrGLFunction<GrGLGetMultisamplefvProc> fGetMultisamplefv;
GrGLFunction<GrGLGetProgramBinaryProc> fGetProgramBinary;
GrGLFunction<GrGLGetProgramInfoLogProc> fGetProgramInfoLog;
GrGLFunction<GrGLGetProgramivProc> fGetProgramiv;
GrGLFunction<GrGLGetQueryObjecti64vProc> fGetQueryObjecti64v;
GrGLFunction<GrGLGetQueryObjectivProc> fGetQueryObjectiv;
GrGLFunction<GrGLGetQueryObjectui64vProc> fGetQueryObjectui64v;
GrGLFunction<GrGLGetQueryObjectuivProc> fGetQueryObjectuiv;
GrGLFunction<GrGLGetQueryivProc> fGetQueryiv;
GrGLFunction<GrGLGetProgramInfoLogProc> fGetProgramInfoLog;
GrGLFunction<GrGLGetProgramivProc> fGetProgramiv;
GrGLFunction<GrGLGetRenderbufferParameterivProc> fGetRenderbufferParameteriv;
GrGLFunction<GrGLGetShaderInfoLogProc> fGetShaderInfoLog;
GrGLFunction<GrGLGetShaderivProc> fGetShaderiv;
@ -202,6 +203,8 @@ public:
GrGLFunction<GrGLIsTextureProc> fIsTexture;
GrGLFunction<GrGLLineWidthProc> fLineWidth;
GrGLFunction<GrGLLinkProgramProc> fLinkProgram;
GrGLFunction<GrGLProgramBinaryProc> fProgramBinary;
GrGLFunction<GrGLProgramParameteriProc> fProgramParameteri;
GrGLFunction<GrGLMapBufferProc> fMapBuffer;
GrGLFunction<GrGLMapBufferRangeProc> fMapBufferRange;
GrGLFunction<GrGLMapBufferSubDataProc> fMapBufferSubData;

View File

@ -213,6 +213,8 @@ bool GrContext::init(const GrContextOptions& options) {
fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
}
fPersistentCache = options.fPersistentCache;
return true;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}
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;
}
// 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<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;
}
}
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<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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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&);

View File

@ -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