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:
parent
b693fbf0fa
commit
d1b2eec0d0
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -213,6 +213,8 @@ bool GrContext::init(const GrContextOptions& options) {
|
||||
fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
|
||||
}
|
||||
|
||||
fPersistentCache = options.fPersistentCache;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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&);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user