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>
This commit is contained in:
parent
7d2ad0fdef
commit
5e7fbfd9b0
@ -337,6 +337,7 @@ private:
|
||||
bool fPMUPMConversionsRoundTrip;
|
||||
|
||||
GrContextOptions::PersistentCache* fPersistentCache;
|
||||
GrContextOptions::ShaderErrorHandler* fShaderErrorHandler;
|
||||
|
||||
// TODO: have the GrClipStackClip use renderTargetContexts and rm this friending
|
||||
friend class GrContextPriv;
|
||||
|
@ -48,6 +48,17 @@ struct SK_API GrContextOptions {
|
||||
virtual void store(const SkData& key, const SkData& data) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract class to report errors when compiling shaders. If fShaderErrorHandler is present,
|
||||
* it will be called to report any compilation failures. Otherwise, failures will be reported
|
||||
* via SkDebugf and asserts.
|
||||
*/
|
||||
class SK_API ShaderErrorHandler {
|
||||
public:
|
||||
virtual ~ShaderErrorHandler() {}
|
||||
virtual void compileError(const char* shader, const char* errors) = 0;
|
||||
};
|
||||
|
||||
GrContextOptions() {}
|
||||
|
||||
// Suppress prints for the GrContext.
|
||||
@ -179,10 +190,10 @@ struct SK_API GrContextOptions {
|
||||
bool fDisallowGLSLBinaryCaching = false;
|
||||
|
||||
/**
|
||||
* Some clients want to ignore shader compilation failures (which might be caused by loss of
|
||||
* context, for example).
|
||||
* If present, use this object to report shader compilation failures. If not, report failures
|
||||
* via SkDebugf and assert.
|
||||
*/
|
||||
bool fAssertOnShaderCompileFailure = true;
|
||||
ShaderErrorHandler* fShaderErrorHandler = nullptr;
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "src/gpu/GrResourceCache.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/GrSemaphore.h"
|
||||
#include "src/gpu/GrShaderUtils.h"
|
||||
#include "src/gpu/GrSoftwarePathRenderer.h"
|
||||
#include "src/gpu/GrTracing.h"
|
||||
#include "src/gpu/SkGr.h"
|
||||
@ -92,6 +93,10 @@ bool GrContext::init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFac
|
||||
}
|
||||
|
||||
fPersistentCache = this->options().fPersistentCache;
|
||||
fShaderErrorHandler = this->options().fShaderErrorHandler;
|
||||
if (!fShaderErrorHandler) {
|
||||
fShaderErrorHandler = GrShaderUtils::DefaultShaderErrorHandler();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -253,6 +253,9 @@ public:
|
||||
void copyOpListsFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest);
|
||||
|
||||
GrContextOptions::PersistentCache* getPersistentCache() { return fContext->fPersistentCache; }
|
||||
GrContextOptions::ShaderErrorHandler* getShaderErrorHandler() const {
|
||||
return fContext->fShaderErrorHandler;
|
||||
}
|
||||
|
||||
#ifdef SK_ENABLE_DUMP_GPU
|
||||
/** Returns a string with detailed information about the context & GPU, in JSON format. */
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/gpu/GrContextOptions.h"
|
||||
#include "src/gpu/GrShaderUtils.h"
|
||||
#include "src/sksl/SkSLString.h"
|
||||
|
||||
@ -190,8 +191,10 @@ SkSL::String PrettyPrint(const SkSL::String& string) {
|
||||
|
||||
// Prints shaders one line at the time. This ensures they don't get truncated by the adb log.
|
||||
void PrintLineByLine(const char* header, const SkSL::String& text) {
|
||||
if (header) {
|
||||
SkDebugf("%s\n", header);
|
||||
}
|
||||
SkSL::String pretty = PrettyPrint(text);
|
||||
SkDebugf("%s\n", header);
|
||||
SkTArray<SkString> lines;
|
||||
SkStrSplit(pretty.c_str(), "\n", kStrict_SkStrSplitMode, &lines);
|
||||
for (int i = 0; i < lines.count(); ++i) {
|
||||
@ -199,4 +202,20 @@ void PrintLineByLine(const char* header, const SkSL::String& text) {
|
||||
}
|
||||
}
|
||||
|
||||
GrContextOptions::ShaderErrorHandler* DefaultShaderErrorHandler() {
|
||||
class GrDefaultShaderErrorHandler : public GrContextOptions::ShaderErrorHandler {
|
||||
public:
|
||||
void compileError(const char* shader, const char* errors) override {
|
||||
SkDebugf("Shader compilation error\n"
|
||||
"------------------------\n");
|
||||
PrintLineByLine(nullptr, shader);
|
||||
SkDebugf("Errors:\n%s\n", errors);
|
||||
SkDEBUGFAIL("Shader compilation failed!");
|
||||
}
|
||||
};
|
||||
|
||||
static GrDefaultShaderErrorHandler gHandler;
|
||||
return &gHandler;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -9,12 +9,14 @@
|
||||
#define GrShaderUtils_DEFINED
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/gpu/GrContextOptions.h"
|
||||
#include "src/sksl/SkSLString.h"
|
||||
|
||||
namespace GrShaderUtils {
|
||||
|
||||
SkSL::String PrettyPrint(const SkSL::String& string);
|
||||
void PrintLineByLine(const char* header, const SkSL::String& text);
|
||||
GrContextOptions::ShaderErrorHandler* DefaultShaderErrorHandler();
|
||||
|
||||
}
|
||||
|
||||
|
@ -3440,24 +3440,23 @@ bool GrGLGpu::createCopyProgram(GrTexture* srcTex) {
|
||||
"}"
|
||||
);
|
||||
|
||||
auto errorHandler = this->getContext()->priv().getShaderErrorHandler();
|
||||
SkSL::String sksl(vshaderTxt.c_str(), vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = shaderCaps;
|
||||
SkSL::String glsl;
|
||||
bool assertOnCompileFailure =
|
||||
this->getContext()->priv().options().fAssertOnShaderCompileFailure;
|
||||
std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kVertex_Kind,
|
||||
sksl, settings, &glsl);
|
||||
sksl, settings, &glsl, errorHandler);
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
|
||||
GR_GL_VERTEX_SHADER, glsl, &fStats,
|
||||
assertOnCompileFailure);
|
||||
GR_GL_VERTEX_SHADER, glsl, &fStats, errorHandler);
|
||||
SkASSERT(program->fInputs.isEmpty());
|
||||
|
||||
sksl.assign(fshaderTxt.c_str(), fshaderTxt.size());
|
||||
program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl);
|
||||
program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl,
|
||||
errorHandler);
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, glsl, &fStats,
|
||||
assertOnCompileFailure);
|
||||
errorHandler);
|
||||
SkASSERT(program->fInputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram));
|
||||
@ -3596,24 +3595,23 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
|
||||
|
||||
fshaderTxt.append("}");
|
||||
|
||||
auto errorHandler = this->getContext()->priv().getShaderErrorHandler();
|
||||
SkSL::String sksl(vshaderTxt.c_str(), vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = shaderCaps;
|
||||
SkSL::String glsl;
|
||||
bool assertOnCompileFailure =
|
||||
this->getContext()->priv().options().fAssertOnShaderCompileFailure;
|
||||
std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kVertex_Kind,
|
||||
sksl, settings, &glsl);
|
||||
sksl, settings, &glsl, errorHandler);
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
|
||||
GR_GL_VERTEX_SHADER, glsl, &fStats,
|
||||
assertOnCompileFailure);
|
||||
GR_GL_VERTEX_SHADER, glsl, &fStats, errorHandler);
|
||||
SkASSERT(program->fInputs.isEmpty());
|
||||
|
||||
sksl.assign(fshaderTxt.c_str(), fshaderTxt.size());
|
||||
program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl);
|
||||
program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl,
|
||||
errorHandler);
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, glsl, &fStats,
|
||||
assertOnCompileFailure);
|
||||
errorHandler);
|
||||
SkASSERT(program->fInputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram));
|
||||
|
@ -89,15 +89,15 @@ bool GrGLProgramBuilder::compileAndAttachShaders(const SkSL::String& glsl,
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
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 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
|
||||
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 @@ void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
|
||||
// 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);
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ private:
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
SkTDArray<GrGLuint>* shaderIds,
|
||||
const SkSL::Program::Inputs& inputs);
|
||||
const SkSL::Program::Inputs& inputs,
|
||||
GrContextOptions::ShaderErrorHandler* errorHandler);
|
||||
|
||||
void computeCountsAndStrides(GrGLuint programID, const GrPrimitiveProcessor& primProc,
|
||||
bool bindAttribLocations);
|
||||
@ -64,7 +65,8 @@ private:
|
||||
const SkSL::String shaders[], bool isSkSL);
|
||||
GrGLProgram* finalize();
|
||||
void bindProgramResourceLocations(GrGLuint programID);
|
||||
bool checkLinkStatus(GrGLuint programID);
|
||||
bool checkLinkStatus(GrGLuint programID, GrContextOptions::ShaderErrorHandler* errorHandler,
|
||||
SkSL::String* sksl[], const SkSL::String glsl[]);
|
||||
void resolveProgramResourceLocations(GrGLuint programID);
|
||||
void cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs);
|
||||
void cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs);
|
||||
|
@ -32,15 +32,14 @@ std::unique_ptr<SkSL::Program> GrSkSLtoGLSL(const GrGLContext& context,
|
||||
SkSL::Program::Kind programKind,
|
||||
const SkSL::String& sksl,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::String* glsl) {
|
||||
SkSL::String* glsl,
|
||||
GrContextOptions::ShaderErrorHandler* errorHandler) {
|
||||
SkSL::Compiler* compiler = context.compiler();
|
||||
std::unique_ptr<SkSL::Program> program;
|
||||
program = compiler->convertProgram(programKind, sksl, settings);
|
||||
if (!program || !compiler->toGLSL(*program, glsl)) {
|
||||
SkDebugf("SKSL compilation error\n----------------------\n");
|
||||
GrShaderUtils::PrintLineByLine("SKSL:", sksl);
|
||||
SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str());
|
||||
SkDEBUGFAIL("SKSL compilation failed!\n");
|
||||
errorHandler->compileError(GrShaderUtils::PrettyPrint(sksl).c_str(),
|
||||
compiler->errorText().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -62,7 +61,7 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GrGLenum type,
|
||||
const SkSL::String& glsl,
|
||||
GrGpu::Stats* stats,
|
||||
bool assertOnFailure) {
|
||||
GrContextOptions::ShaderErrorHandler* errorHandler) {
|
||||
const GrGLInterface* gli = glCtx.interface();
|
||||
|
||||
// Specify GLSL source to the driver.
|
||||
@ -88,8 +87,6 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));
|
||||
|
||||
if (!compiled) {
|
||||
SkDebugf("GLSL compilation error\n----------------------\n");
|
||||
GrShaderUtils::PrintLineByLine("GLSL:", 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
|
||||
@ -98,13 +95,8 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
// buffer param validation.
|
||||
GrGLsizei length = GR_GL_INIT_ZERO;
|
||||
GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get()));
|
||||
SkDebugf("Errors:\n%s\n", (const char*) log.get());
|
||||
}
|
||||
// In Chrome we may have failed due to context-loss. So we should just continue along
|
||||
// wihthout asserting until the GrContext gets abandoned.
|
||||
if (assertOnFailure && kChromium_GrGLDriver != glCtx.driver()) {
|
||||
SkDEBUGFAIL("GLSL compilation failed!");
|
||||
}
|
||||
errorHandler->compileError(glsl.c_str(), infoLen > 0 ? (const char*)log.get() : "");
|
||||
GR_GL_CALL(gli, DeleteShader(shaderId));
|
||||
return 0;
|
||||
}
|
||||
@ -117,13 +109,3 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GR_GL_CALL(gli, AttachShader(programId, shaderId));
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
void GrGLPrintShader(const GrGLContext& context, SkSL::Program::Kind programKind,
|
||||
const SkSL::String& sksl, const SkSL::Program::Settings& settings) {
|
||||
print_shader_banner(programKind);
|
||||
GrShaderUtils::PrintLineByLine("SKSL:", sksl);
|
||||
SkSL::String glsl;
|
||||
if (GrSkSLtoGLSL(context, programKind, sksl, settings, &glsl)) {
|
||||
GrShaderUtils::PrintLineByLine("GLSL:", glsl);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define GrGLShaderStringBuilder_DEFINED
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/gpu/GrContextOptions.h"
|
||||
#include "src/gpu/GrAllocator.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/gl/GrGLContext.h"
|
||||
@ -18,16 +19,14 @@ std::unique_ptr<SkSL::Program> GrSkSLtoGLSL(const GrGLContext& context,
|
||||
SkSL::Program::Kind programKind,
|
||||
const SkSL::String& sksl,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::String* glsl);
|
||||
SkSL::String* glsl,
|
||||
GrContextOptions::ShaderErrorHandler* errorHandler);
|
||||
|
||||
GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
const SkSL::String& glsl,
|
||||
GrGpu::Stats*,
|
||||
bool assertOnFailure);
|
||||
|
||||
void GrGLPrintShader(const GrGLContext&, SkSL::Program::Kind programKind, const SkSL::String& sksl,
|
||||
const SkSL::Program::Settings&);
|
||||
GrContextOptions::ShaderErrorHandler* errorHandler);
|
||||
|
||||
#endif
|
||||
|
@ -106,9 +106,7 @@ static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V')
|
||||
static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
|
||||
|
||||
int GrVkPipelineStateBuilder::loadShadersFromCache(const SkData& cached,
|
||||
VkShaderModule* outVertShaderModule,
|
||||
VkShaderModule* outFragShaderModule,
|
||||
VkShaderModule* outGeomShaderModule,
|
||||
VkShaderModule outShaderModules[],
|
||||
VkPipelineShaderStageCreateInfo* outStageInfo) {
|
||||
SkSL::String shaders[kGrShaderTypeCount];
|
||||
SkSL::Program::Inputs inputs[kGrShaderTypeCount];
|
||||
@ -120,14 +118,14 @@ int GrVkPipelineStateBuilder::loadShadersFromCache(const SkData& cached,
|
||||
|
||||
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
|
||||
fVS,
|
||||
outVertShaderModule,
|
||||
&outShaderModules[kVertex_GrShaderType],
|
||||
&outStageInfo[0],
|
||||
shaders[kVertex_GrShaderType],
|
||||
inputs[kVertex_GrShaderType]));
|
||||
|
||||
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
fFS,
|
||||
outFragShaderModule,
|
||||
&outShaderModules[kFragment_GrShaderType],
|
||||
&outStageInfo[1],
|
||||
shaders[kFragment_GrShaderType],
|
||||
inputs[kFragment_GrShaderType]));
|
||||
@ -135,7 +133,7 @@ int GrVkPipelineStateBuilder::loadShadersFromCache(const SkData& cached,
|
||||
if (!shaders[kGeometry_GrShaderType].empty()) {
|
||||
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
fGS,
|
||||
outGeomShaderModule,
|
||||
&outShaderModules[kGeometry_GrShaderType],
|
||||
&outStageInfo[2],
|
||||
shaders[kGeometry_GrShaderType],
|
||||
inputs[kGeometry_GrShaderType]));
|
||||
@ -162,9 +160,9 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
Desc* desc) {
|
||||
VkDescriptorSetLayout dsLayout[2];
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkShaderModule vertShaderModule = VK_NULL_HANDLE;
|
||||
VkShaderModule geomShaderModule = VK_NULL_HANDLE;
|
||||
VkShaderModule fragShaderModule = VK_NULL_HANDLE;
|
||||
VkShaderModule shaderModules[kGrShaderTypeCount] = { VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE };
|
||||
|
||||
GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
|
||||
// These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed
|
||||
@ -221,8 +219,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
#endif
|
||||
int numShaderStages = 0;
|
||||
if (cached && binaryCache) {
|
||||
numShaderStages = this->loadShadersFromCache(*cached, &vertShaderModule, &fragShaderModule,
|
||||
&geomShaderModule, shaderStageInfo);
|
||||
numShaderStages = this->loadShadersFromCache(*cached, shaderModules, shaderStageInfo);
|
||||
}
|
||||
|
||||
if (!numShaderStages) {
|
||||
@ -247,35 +244,48 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
}
|
||||
#endif
|
||||
|
||||
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
|
||||
bool success = this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
|
||||
*sksl[kVertex_GrShaderType],
|
||||
&vertShaderModule,
|
||||
&shaderModules[kVertex_GrShaderType],
|
||||
&shaderStageInfo[0],
|
||||
settings,
|
||||
desc,
|
||||
&shaders[kVertex_GrShaderType],
|
||||
&inputs[kVertex_GrShaderType]));
|
||||
&inputs[kVertex_GrShaderType]);
|
||||
|
||||
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
*sksl[kFragment_GrShaderType],
|
||||
&fragShaderModule,
|
||||
&shaderStageInfo[1],
|
||||
settings,
|
||||
desc,
|
||||
&shaders[kFragment_GrShaderType],
|
||||
&inputs[kFragment_GrShaderType]));
|
||||
success = success && this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
*sksl[kFragment_GrShaderType],
|
||||
&shaderModules[kFragment_GrShaderType],
|
||||
&shaderStageInfo[1],
|
||||
settings,
|
||||
desc,
|
||||
&shaders[kFragment_GrShaderType],
|
||||
&inputs[kFragment_GrShaderType]);
|
||||
|
||||
if (this->primitiveProcessor().willUseGeoShader()) {
|
||||
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
*sksl[kGeometry_GrShaderType],
|
||||
&geomShaderModule,
|
||||
&shaderStageInfo[2],
|
||||
settings,
|
||||
desc,
|
||||
&shaders[kGeometry_GrShaderType],
|
||||
&inputs[kGeometry_GrShaderType]));
|
||||
success = success && this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
*sksl[kGeometry_GrShaderType],
|
||||
&shaderModules[kGeometry_GrShaderType],
|
||||
&shaderStageInfo[2],
|
||||
settings,
|
||||
desc,
|
||||
&shaders[kGeometry_GrShaderType],
|
||||
&inputs[kGeometry_GrShaderType]);
|
||||
++numShaderStages;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
for (int i = 0; i < kGrShaderTypeCount; ++i) {
|
||||
if (shaderModules[i]) {
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(),
|
||||
shaderModules[i], nullptr));
|
||||
}
|
||||
}
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout,
|
||||
nullptr));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (persistentCache && !cached) {
|
||||
bool isSkSL = false;
|
||||
#if GR_TEST_UTILS
|
||||
@ -292,15 +302,13 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
GrVkPipeline* pipeline = resourceProvider.createPipeline(
|
||||
this->renderTarget()->numColorSamples(), fPrimProc, fPipeline, stencil, this->origin(),
|
||||
shaderStageInfo, numShaderStages, primitiveType, compatibleRenderPass, pipelineLayout);
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), vertShaderModule,
|
||||
nullptr));
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), fragShaderModule,
|
||||
nullptr));
|
||||
// This if check should not be needed since calling destroy on a VK_NULL_HANDLE is allowed.
|
||||
// However this is causing a crash in certain drivers (e.g. NVidia).
|
||||
if (this->primitiveProcessor().willUseGeoShader()) {
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), geomShaderModule,
|
||||
nullptr));
|
||||
for (int i = 0; i < kGrShaderTypeCount; ++i) {
|
||||
// This if check should not be needed since calling destroy on a VK_NULL_HANDLE is allowed.
|
||||
// However this is causing a crash in certain drivers (e.g. NVidia).
|
||||
if (shaderModules[i]) {
|
||||
GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), shaderModules[i],
|
||||
nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
if (!pipeline) {
|
||||
|
@ -91,10 +91,7 @@ private:
|
||||
Desc*);
|
||||
|
||||
// returns number of shader stages
|
||||
int loadShadersFromCache(const SkData& cached,
|
||||
VkShaderModule* outVertShaderModule,
|
||||
VkShaderModule* outFragShaderModule,
|
||||
VkShaderModule* outGeomShaderModule,
|
||||
int loadShadersFromCache(const SkData& cached, VkShaderModule outShaderModules[],
|
||||
VkPipelineShaderStageCreateInfo* outStageInfo);
|
||||
|
||||
void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[],
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/gpu/vk/GrVkUtil.h"
|
||||
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
#include "src/gpu/vk/GrVkGpu.h"
|
||||
#include "src/sksl/SkSLCompiler.h"
|
||||
|
||||
@ -207,16 +208,18 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::String* outSPIRV,
|
||||
SkSL::Program::Inputs* outInputs) {
|
||||
auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler();
|
||||
std::unique_ptr<SkSL::Program> program = gpu->shaderCompiler()->convertProgram(
|
||||
vk_shader_stage_to_skiasl_kind(stage), shaderString, settings);
|
||||
if (!program) {
|
||||
printf("%s\n", shaderString.c_str());
|
||||
SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
|
||||
SkASSERT(false);
|
||||
errorHandler->compileError(shaderString.c_str(),
|
||||
gpu->shaderCompiler()->errorText().c_str());
|
||||
return false;
|
||||
}
|
||||
*outInputs = program->fInputs;
|
||||
if (!gpu->shaderCompiler()->toSPIRV(*program, outSPIRV)) {
|
||||
SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
|
||||
errorHandler->compileError(shaderString.c_str(),
|
||||
gpu->shaderCompiler()->errorText().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,24 @@
|
||||
#include "tools/viewer/NIMASlide.h"
|
||||
#endif
|
||||
|
||||
class CapturingShaderErrorHandler : public GrContextOptions::ShaderErrorHandler {
|
||||
public:
|
||||
void compileError(const char* shader, const char* errors) override {
|
||||
fShaders.push_back(SkString(shader));
|
||||
fErrors.push_back(SkString(errors));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
fShaders.reset();
|
||||
fErrors.reset();
|
||||
}
|
||||
|
||||
SkTArray<SkString> fShaders;
|
||||
SkTArray<SkString> fErrors;
|
||||
};
|
||||
|
||||
static CapturingShaderErrorHandler gShaderErrorHandler;
|
||||
|
||||
using namespace sk_app;
|
||||
|
||||
static std::map<GpuPathRenderers, std::string> gPathRendererNames;
|
||||
@ -281,6 +299,8 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
|
||||
SetCtxOptionsFromCommonFlags(&displayParams.fGrContextOptions);
|
||||
displayParams.fGrContextOptions.fPersistentCache = &fPersistentCache;
|
||||
displayParams.fGrContextOptions.fDisallowGLSLBinaryCaching = true;
|
||||
displayParams.fGrContextOptions.fShaderErrorHandler = &gShaderErrorHandler;
|
||||
displayParams.fGrContextOptions.fSuppressPrints = true;
|
||||
fWindow->setRequestedDisplayParams(displayParams);
|
||||
|
||||
// Configure timers
|
||||
@ -2062,6 +2082,17 @@ void Viewer::drawImGui() {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (gShaderErrorHandler.fErrors.count()) {
|
||||
ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Shader Errors");
|
||||
for (int i = 0; i < gShaderErrorHandler.fErrors.count(); ++i) {
|
||||
ImGui::TextWrapped("%s", gShaderErrorHandler.fErrors[i].c_str());
|
||||
ImGui::TextWrapped("%s", gShaderErrorHandler.fShaders[i].c_str());
|
||||
}
|
||||
ImGui::End();
|
||||
gShaderErrorHandler.reset();
|
||||
}
|
||||
|
||||
if (fShowZoomWindow && fLastImage) {
|
||||
ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Zoom", &fShowZoomWindow)) {
|
||||
|
Loading…
Reference in New Issue
Block a user