Add ShaderErrorHandler to GrContextOptions
Allows clients to customize behavior when shaders fail to compile.
Added nicer shader error handling to viewer.
Change-Id: If82b48e40d64fd786f37e88c564fd623b53c7f9d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211361
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index d7ac7e4..bed69a3 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -89,15 +89,15 @@
GrGLuint programId,
GrGLenum type,
SkTDArray<GrGLuint>* shaderIds,
- const SkSL::Program::Inputs& inputs) {
+ const SkSL::Program::Inputs& inputs,
+ GrContextOptions::ShaderErrorHandler* errHandler) {
GrGLGpu* gpu = this->gpu();
- bool assertOnCompileFailure = gpu->getContext()->priv().options().fAssertOnShaderCompileFailure;
GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
programId,
type,
glsl,
gpu->stats(),
- assertOnCompileFailure);
+ errHandler);
if (!shaderId) {
return false;
}
@@ -202,6 +202,7 @@
this->finalizeShaders();
// compile shaders and bind attributes / uniforms
+ auto errorHandler = this->gpu()->getContext()->priv().getShaderErrorHandler();
const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
SkSL::Program::Settings settings;
settings.fCaps = this->gpu()->glCaps().shaderCaps();
@@ -241,7 +242,7 @@
length));
if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
if (checkLinked) {
- cached = this->checkLinkStatus(programID);
+ cached = this->checkLinkStatus(programID, errorHandler, nullptr, nullptr);
}
if (cached) {
this->addInputVars(inputs);
@@ -284,7 +285,8 @@
SkSL::Program::kFragment_Kind,
*sksl[kFragment_GrShaderType],
settings,
- &glsl[kFragment_GrShaderType]);
+ &glsl[kFragment_GrShaderType],
+ errorHandler);
if (!fs) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
@@ -297,7 +299,8 @@
this->computeCountsAndStrides(programID, primProc, false);
}
if (!this->compileAndAttachShaders(glsl[kFragment_GrShaderType], programID,
- GR_GL_FRAGMENT_SHADER, &shadersToDelete, inputs)) {
+ GR_GL_FRAGMENT_SHADER, &shadersToDelete, inputs,
+ errorHandler)) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
}
@@ -308,14 +311,16 @@
SkSL::Program::kVertex_Kind,
*sksl[kVertex_GrShaderType],
settings,
- &glsl[kVertex_GrShaderType]);
+ &glsl[kVertex_GrShaderType],
+ errorHandler);
if (!vs) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
}
}
if (!this->compileAndAttachShaders(glsl[kVertex_GrShaderType], programID,
- GR_GL_VERTEX_SHADER, &shadersToDelete, inputs)) {
+ GR_GL_VERTEX_SHADER, &shadersToDelete, inputs,
+ errorHandler)) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
}
@@ -334,14 +339,16 @@
SkSL::Program::kGeometry_Kind,
*sksl[kGeometry_GrShaderType],
settings,
- &glsl[kGeometry_GrShaderType]);
+ &glsl[kGeometry_GrShaderType],
+ errorHandler);
if (!gs) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
}
}
if (!this->compileAndAttachShaders(glsl[kGeometry_GrShaderType], programID,
- GR_GL_GEOMETRY_SHADER, &shadersToDelete, inputs)) {
+ GR_GL_GEOMETRY_SHADER, &shadersToDelete, inputs,
+ errorHandler)) {
this->cleanupProgram(programID, shadersToDelete);
return nullptr;
}
@@ -350,22 +357,8 @@
GL_CALL(LinkProgram(programID));
if (checkLinked) {
- if (!this->checkLinkStatus(programID)) {
+ if (!this->checkLinkStatus(programID, errorHandler, sksl, glsl)) {
GL_CALL(DeleteProgram(programID));
- GrGLPrintShader(fGpu->glContext(),
- SkSL::Program::kVertex_Kind,
- fVS.fCompilerString,
- settings);
- if (primProc.willUseGeoShader()) {
- GrGLPrintShader(fGpu->glContext(),
- SkSL::Program::kGeometry_Kind,
- fGS.fCompilerString,
- settings);
- }
- GrGLPrintShader(fGpu->glContext(),
- SkSL::Program::kFragment_Kind,
- fFS.fCompilerString,
- settings);
return nullptr;
}
}
@@ -414,11 +407,27 @@
}
}
-bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
+bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
+ GrContextOptions::ShaderErrorHandler* errorHandler,
+ SkSL::String* sksl[], const SkSL::String glsl[]) {
GrGLint linked = GR_GL_INIT_ZERO;
GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
if (!linked) {
- SkDebugf("Program linking failed.\n");
+ SkSL::String allShaders;
+ if (sksl) {
+ allShaders.appendf("// Vertex SKSL\n%s\n", sksl[kVertex_GrShaderType]->c_str());
+ if (!sksl[kGeometry_GrShaderType]->empty()) {
+ allShaders.appendf("// Geometry SKSL\n%s\n", sksl[kGeometry_GrShaderType]->c_str());
+ }
+ allShaders.appendf("// Fragment SKSL\n%s\n", sksl[kFragment_GrShaderType]->c_str());
+ }
+ if (glsl) {
+ allShaders.appendf("// Vertex GLSL\n%s\n", glsl[kVertex_GrShaderType].c_str());
+ if (!glsl[kGeometry_GrShaderType].empty()) {
+ allShaders.appendf("// Geometry GLSL\n%s\n", glsl[kGeometry_GrShaderType].c_str());
+ }
+ allShaders.appendf("// Fragment GLSL\n%s\n", glsl[kFragment_GrShaderType].c_str());
+ }
GrGLint infoLen = GR_GL_INIT_ZERO;
GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
@@ -426,12 +435,9 @@
// retrieve length even though we don't need it to workaround
// bug in chrome cmd buffer param validation.
GrGLsizei length = GR_GL_INIT_ZERO;
- GL_CALL(GetProgramInfoLog(programID,
- infoLen+1,
- &length,
- (char*)log.get()));
- SkDebugf("%s", (char*)log.get());
+ GL_CALL(GetProgramInfoLog(programID, infoLen+1, &length, (char*)log.get()));
}
+ errorHandler->compileError(allShaders.c_str(), infoLen > 0 ? (const char*)log.get() : "");
}
return SkToBool(linked);
}