diff options
author | Brian Salomon <bsalomon@google.com> | 2017-05-15 11:00:58 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-05-15 15:41:01 +0000 |
commit | e334c596546c7ec79f2b0e55b3a1c2839a94f352 (patch) | |
tree | e84c3c7209693de32ec8722d09d6e1bafbee74ad /src/gpu/gl/builders | |
parent | 63cef6b8c11b8f5d5584a13929e218f520a49669 (diff) |
Attempt to work around iOS varying limit in GLPrograms test
Dump shaders when linking fails.
Bug: skia:6627
Change-Id: I7f1df4be039eb56d990aa64c58c8dd2a22d97dbe
Reviewed-on: https://skia-review.googlesource.com/16867
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src/gpu/gl/builders')
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.cpp | 22 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLSLPrettyPrint.cpp | 204 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLShaderStringBuilder.cpp | 135 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLShaderStringBuilder.h | 5 |
4 files changed, 109 insertions, 257 deletions
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 79cb2cab83..f63e56b7d1 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -19,7 +19,6 @@ #include "SkTraceEvent.h" #include "gl/GrGLGpu.h" #include "gl/GrGLProgram.h" -#include "gl/GrGLSLPrettyPrint.h" #include "gl/builders/GrGLShaderStringBuilder.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" @@ -158,7 +157,24 @@ GrGLProgram* GrGLProgramBuilder::finalize() { checkLinked = true; #endif if (checkLinked) { - checkLinkStatus(programID); + if (!this->checkLinkStatus(programID)) { + SkDebugf("VS:\n"); + GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(), + fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(), + settings); + if (primProc.willUseGeoShader()) { + SkDebugf("\nGS:\n"); + GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER, + fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(), + fGS.fCompilerStrings.count(), settings); + } + SkDebugf("\nFS:\n"); + GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(), + fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(), + settings); + SkDEBUGFAIL(""); + return nullptr; + } } this->resolveProgramResourceLocations(programID); @@ -197,6 +213,7 @@ bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) { GrGLint linked = GR_GL_INIT_ZERO; GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked)); if (!linked) { + SkDebugf("Program linking failed.\n"); 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 @@ -210,7 +227,6 @@ bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) { (char*)log.get())); SkDebugf("%s", (char*)log.get()); } - SkDEBUGFAIL("Error linking program"); GL_CALL(DeleteProgram(programID)); programID = 0; } diff --git a/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp b/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp deleted file mode 100644 index 02802987c6..0000000000 --- a/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "gl/GrGLSLPrettyPrint.h" - -namespace GrGLSLPrettyPrint { - -class GLSLPrettyPrint { -public: - GLSLPrettyPrint() {} - - SkString prettify(const char** strings, - int* lengths, - int count, - bool countlines) { - fCountlines = countlines; - fTabs = 0; - fLinecount = 1; - fFreshline = true; - - // If a string breaks while in the middle 'parse until' we need to continue parsing on the - // next string - fInParseUntilNewline = false; - fInParseUntil = false; - - int parensDepth = 0; - - // number 1st line - this->lineNumbering(); - for (int i = 0; i < count; i++) { - // setup pretty state - fIndex = 0; - fLength = lengths[i]; - fInput = strings[i]; - - while (fLength > fIndex) { - /* the heart and soul of our prettification algorithm. The rules should hopefully - * be self explanatory. For '#' and '//' tokens we parse until we reach a newline. - * - * For long style comments like this one, we search for the ending token. We also - * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines - * ourselves. This allows us to remain in control of line numbers, and matching - * tabs Existing tabs in the input string are copied over too, but this will look - * funny - * - * '{' and '}' are handled in basically the same way. We add a newline if we aren't - * on a fresh line, dirty the line, then add a second newline, ie braces are always - * on their own lines indented properly. The one funkiness here is structs print - * with the semicolon on its own line. Its not a problem for a glsl compiler though - * - * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala - * in for loops. - * - * ';' means add a new line - * - * '\t' and '\n' are ignored in general parsing for backwards compatability with - * existing shader code and we also have a special case for handling whitespace - * at the beginning of fresh lines. - * - * Otherwise just add the new character to the pretty string, indenting if necessary. - */ - if (fInParseUntilNewline) { - this->parseUntilNewline(); - } else if (fInParseUntil) { - this->parseUntil(fInParseUntilToken); - } else if (this->hasToken("#") || this->hasToken("//")) { - this->parseUntilNewline(); - } else if (this->hasToken("/*")) { - this->parseUntil("*/"); - } else if ('{' == fInput[fIndex]) { - this->newline(); - this->appendChar('{'); - fTabs++; - this->newline(); - } else if ('}' == fInput[fIndex]) { - fTabs--; - this->newline(); - this->appendChar('}'); - this->newline(); - } else if (this->hasToken(")")) { - parensDepth--; - } else if (this->hasToken("(")) { - parensDepth++; - } else if (!parensDepth && this->hasToken(";")) { - this->newline(); - } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] || - (fFreshline && ' ' == fInput[fIndex])) { - fIndex++; - } else { - this->appendChar(fInput[fIndex]); - } - } - } - return fPretty; - } -private: - void appendChar(char c) { - this->tabString(); - fPretty.appendf("%c", fInput[fIndex++]); - fFreshline = false; - } - - // hasToken automatically consumes the next token, if it is a match, and then tabs - // if necessary, before inserting the token into the pretty string - bool hasToken(const char* token) { - size_t i = fIndex; - for (size_t j = 0; token[j] && fLength > i; i++, j++) { - if (token[j] != fInput[i]) { - return false; - } - } - this->tabString(); - fIndex = i; - fPretty.append(token); - fFreshline = false; - return true; - } - - void parseUntilNewline() { - while (fLength > fIndex) { - if ('\n' == fInput[fIndex]) { - fIndex++; - this->newline(); - fInParseUntilNewline = false; - break; - } - fPretty.appendf("%c", fInput[fIndex++]); - fInParseUntilNewline = true; - } - } - - // this code assumes it is not actually searching for a newline. If you need to search for a - // newline, then use the function above. If you do search for a newline with this function - // it will consume the entire string and the output will certainly not be prettified - void parseUntil(const char* token) { - while (fLength > fIndex) { - // For embedded newlines, this code will make sure to embed the newline in the - // pretty string, increase the linecount, and tab out the next line to the appropriate - // place - if ('\n' == fInput[fIndex]) { - this->newline(); - this->tabString(); - fIndex++; - } - if (this->hasToken(token)) { - fInParseUntil = false; - break; - } - fFreshline = false; - fPretty.appendf("%c", fInput[fIndex++]); - fInParseUntil = true; - fInParseUntilToken = token; - } - } - - // We only tab if on a newline, otherwise consider the line tabbed - void tabString() { - if (fFreshline) { - for (int t = 0; t < fTabs; t++) { - fPretty.append("\t"); - } - } - } - - // newline is really a request to add a newline, if we are on a fresh line there is no reason - // to add another newline - void newline() { - if (!fFreshline) { - fFreshline = true; - fPretty.append("\n"); - this->lineNumbering(); - } - } - - void lineNumbering() { - if (fCountlines) { - fPretty.appendf("%4d\t", fLinecount++); - } - } - - bool fCountlines, fFreshline; - int fTabs, fLinecount; - size_t fIndex, fLength; - const char* fInput; - SkString fPretty; - - // Some helpers for parseUntil when we go over a string length - bool fInParseUntilNewline; - bool fInParseUntil; - const char* fInParseUntilToken; -}; - -SkString PrettyPrintGLSL(const char** strings, - int* lengths, - int count, - bool countlines) { - GLSLPrettyPrint pp; - return pp.prettify(strings, lengths, count, countlines); -} - -} // end namespace diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp index e3d2defdef..eb320d3b30 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp @@ -6,12 +6,12 @@ */ #include "GrGLShaderStringBuilder.h" +#include "GrSKSLPrettyPrint.h" #include "SkAutoMalloc.h" #include "SkSLCompiler.h" #include "SkSLGLSLCodeGenerator.h" #include "SkTraceEvent.h" #include "gl/GrGLGpu.h" -#include "gl/GrGLSLPrettyPrint.h" #include "ir/SkSLProgram.h" #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) @@ -20,68 +20,103 @@ // Print the source code for all shaders generated. static const bool c_PrintShaders{false}; -static void print_source_with_line_numbers(const SkString&); - -GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, - GrGLuint programId, - GrGLenum type, - const char** strings, - int* lengths, - int count, - GrGpu::Stats* stats, - const SkSL::Program::Settings& settings, - SkSL::Program::Inputs* outInputs) { - const GrGLInterface* gli = glCtx.interface(); +static SkString list_source_with_line_numbers(const char* source) { + SkTArray<SkString> lines; + SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines); + SkString result; + for (int line = 0; line < lines.count(); ++line) { + // Print the shader one line at the time so it doesn't get truncated by the adb log. + result.appendf("%4i\t%s\n", line + 1, lines[line].c_str()); + } + return result; +} - GrGLuint shaderId; - GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); - if (0 == shaderId) { - return 0; +SkString list_shaders(const char** skslStrings, int* lengths, int count, const SkSL::String& glsl) { + SkString sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false); + SkString result("SKSL:\n"); + result.append(list_source_with_line_numbers(sksl.c_str())); + if (!glsl.isEmpty()) { + result.append("GLSL:\n"); + result.append(list_source_with_line_numbers(glsl.c_str())); } + return result; +} +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) { SkString sksl; #ifdef SK_DEBUG - sksl = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false); + sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false); #else for (int i = 0; i < count; i++) { - sksl.append(strings[i], lengths[i]); + sksl.append(skslStrings[i], lengths[i]); } #endif - - SkSL::String glsl; if (type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER) { - SkSL::Compiler& compiler = *glCtx.compiler(); + SkSL::Compiler* compiler = context.compiler(); std::unique_ptr<SkSL::Program> program; - program = compiler.convertProgram( - type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind - : SkSL::Program::kFragment_Kind, - sksl, - settings); - if (!program || !compiler.toGLSL(*program, &glsl)) { + program = compiler->convertProgram(type == GR_GL_VERTEX_SHADER + ? SkSL::Program::kVertex_Kind + : SkSL::Program::kFragment_Kind, + sksl, + settings); + if (!program || !compiler->toGLSL(*program, glsl)) { SkDebugf("SKSL compilation error\n----------------------\n"); - SkDebugf("SKSL:\n"); - print_source_with_line_numbers(sksl); - SkDebugf("\nErrors:\n%s\n", compiler.errorText().c_str()); + SkDebugf(list_shaders(skslStrings, lengths, count, *glsl).c_str()); + SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str()); SkDEBUGFAIL("SKSL compilation failed!\n"); + return nullptr; } - *outInputs = program->fInputs; + return program; } else { // TODO: geometry shader support in sksl. SkASSERT(type == GR_GL_GEOMETRY_SHADER); - glsl = sksl; + return nullptr; } +} +GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, + GrGLuint programId, + GrGLenum type, + const char** skslStrings, + int* lengths, + int count, + GrGpu::Stats* stats, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs) { + 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)); - // If tracing is enabled in chrome then we pretty print + // Lazy initialized pretty-printed shaders for dumping. + SkString shaderDebugString; + + // Trace event for shader preceding driver compilation bool traceShader; TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader); if (traceShader) { - SkString shader = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false); + if (shaderDebugString.isEmpty()) { + shaderDebugString = list_shaders(skslStrings, lengths, count, glsl); + } TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader", - TRACE_EVENT_SCOPE_THREAD, "shader", TRACE_STR_COPY(shader.c_str())); + TRACE_EVENT_SCOPE_THREAD, "shader", + TRACE_STR_COPY(shaderDebugString.c_str())); } stats->incShaderCompilations(); @@ -97,6 +132,11 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); if (!compiled) { + if (shaderDebugString.isEmpty()) { + shaderDebugString = list_shaders(skslStrings, lengths, count, glsl); + } + SkDebugf("GLSL compilation error\n----------------------\n"); + SkDebugf(shaderDebugString.c_str()); 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 @@ -105,11 +145,6 @@ 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("GLSL compilation error\n----------------------\n"); - SkDebugf("SKSL:\n"); - print_source_with_line_numbers(sksl); - SkDebugf("GLSL:\n"); - print_source_with_line_numbers(glsl); SkDebugf("Errors:\n%s\n", (const char*) log.get()); } SkDEBUGFAIL("GLSL compilation failed!"); @@ -126,7 +161,10 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break; } SkDebugf("---- %s shader ----------------------------------------------------\n", typeName); - print_source_with_line_numbers(sksl); + if (shaderDebugString.isEmpty()) { + shaderDebugString = list_shaders(skslStrings, lengths, count, glsl); + } + SkDebugf(shaderDebugString.c_str()); } // Attach the shader, but defer deletion until after we have linked the program. @@ -134,15 +172,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; } -static void print_source_with_line_numbers(const SkString& source) { - SkTArray<SkString> lines; - SkStrSplit(source.c_str(), "\n", kStrict_SkStrSplitMode, &lines); - for (int line = 0; line < lines.count(); ++line) { - // Print the shader one line at the time so it doesn't get truncated by the adb log. - SkDebugf("%4i\t%s\n", line + 1, lines[line].c_str()); +void GrGLPrintShader(const GrGLContext& context, GrGLenum type, const char** skslStrings, + int* lengths, int count, const SkSL::Program::Settings& settings) { + SkSL::String glsl; + if (translate_to_glsl(context, type, skslStrings, lengths, count, settings, &glsl)) { + SkDebugf(list_shaders(skslStrings, lengths, count, glsl).c_str()); } } diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.h b/src/gpu/gl/builders/GrGLShaderStringBuilder.h index 242fe617e0..59dea35b8d 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.h +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.h @@ -17,11 +17,14 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GrGLuint programId, GrGLenum type, - const char** strings, + const char** skslStrings, int* lengths, int count, GrGpu::Stats*, const SkSL::Program::Settings& settings, SkSL::Program::Inputs* inputs); +void GrGLPrintShader(const GrGLContext&, GrGLenum type, const char** skslStrings, int* lengths, + int count, const SkSL::Program::Settings&); + #endif |