diff options
author | joshualitt <joshualitt@chromium.org> | 2014-08-08 09:41:42 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-08 09:41:42 -0700 |
commit | bab82ed05b304504e3b5d317486e152dce107313 (patch) | |
tree | 27bbabe32efe1ef35bafa1db8e52ba2f8d03ec07 /src/gpu/gl | |
parent | dff491ba3eab17d5ae631e8c46f83a82390213b8 (diff) |
Pretty print of shaders
BUG=skia:
R=bsalomon@chromium.org, senorblanco@chromium.org, bsalomon@google.com
Author: joshualitt@chromium.org
Review URL: https://codereview.chromium.org/437593004
Diffstat (limited to 'src/gpu/gl')
-rw-r--r-- | src/gpu/gl/GrGLSLPrettyPrint.cpp | 173 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 13 |
2 files changed, 183 insertions, 3 deletions
diff --git a/src/gpu/gl/GrGLSLPrettyPrint.cpp b/src/gpu/gl/GrGLSLPrettyPrint.cpp new file mode 100644 index 0000000000..27f4b44e66 --- /dev/null +++ b/src/gpu/gl/GrGLSLPrettyPrint.cpp @@ -0,0 +1,173 @@ +/* + * 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 SkString& input, bool countlines) { + // setup pretty state + fIndex = 0; + fLength = input.size(); + fInput = input; + fCountlines = countlines; + fTabs = 0; + fLinecount = 1; + fFreshline = true; + + int parensDepth = 0; + // number 1st line + this->lineNumbering(); + 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 (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(input[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(); + break; + } + fPretty.appendf("%c", fInput[fIndex++]); + } + } + + // 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)) { + break; + } + fFreshline = false; + fPretty.appendf("%c", fInput[fIndex++]); + } + } + + // 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; + SkString fInput, fPretty; +}; + +SkString PrettyPrintGLSL(const SkString& input, bool countlines) { + GLSLPrettyPrint pp; + return pp.prettify(input, countlines); +} + +} // end namespace diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index fe9a66ae42..9fffd26145 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -7,6 +7,7 @@ #include "gl/GrGLShaderBuilder.h" #include "gl/GrGLProgram.h" +#include "gl/GrGLSLPrettyPrint.h" #include "gl/GrGLUniformHandle.h" #include "GrCoordTransform.h" #include "GrDrawEffect.h" @@ -671,8 +672,14 @@ static GrGLuint attach_shader(const GrGLContext& glCtx, return 0; } - const GrGLchar* sourceStr = shaderSrc.c_str(); +#ifdef SK_DEBUG + SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, false); + const GrGLchar* sourceStr = prettySource.c_str(); + GrGLint sourceLength = static_cast<GrGLint>(prettySource.size()); +#else GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size()); + const GrGLchar* sourceStr = shaderSrc.c_str(); +#endif GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); GR_GL_CALL(gli, CompileShader(shaderId)); @@ -695,7 +702,7 @@ static GrGLuint attach_shader(const GrGLContext& glCtx, GrGLsizei length = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get())); - GrPrintf(shaderSrc.c_str()); + GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str()); GrPrintf("\n%s", log.get()); } SkDEBUGFAIL("Shader compilation failed!"); @@ -707,7 +714,7 @@ static GrGLuint attach_shader(const GrGLContext& glCtx, TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader", TRACE_EVENT_SCOPE_THREAD, "shader", TRACE_STR_COPY(shaderSrc.c_str())); if (c_PrintShaders) { - GrPrintf(shaderSrc.c_str()); + GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str()); GrPrintf("\n"); } |