aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/gl/builders
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-05-15 11:00:58 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-15 15:41:01 +0000
commite334c596546c7ec79f2b0e55b3a1c2839a94f352 (patch)
treee84c3c7209693de32ec8722d09d6e1bafbee74ad /src/gpu/gl/builders
parent63cef6b8c11b8f5d5584a13929e218f520a49669 (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.cpp22
-rw-r--r--src/gpu/gl/builders/GrGLSLPrettyPrint.cpp204
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.cpp135
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.h5
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