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:
Brian Osman 2019-05-03 13:13:35 -04:00 committed by Skia Commit-Bot
parent 7d2ad0fdef
commit 5e7fbfd9b0
15 changed files with 195 additions and 128 deletions

View File

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

View File

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

View File

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

View File

@ -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. */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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[],

View File

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

View File

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