aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/gl
diff options
context:
space:
mode:
authorGravatar joshualitt <joshualitt@chromium.org>2014-08-08 09:41:42 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-08 09:41:42 -0700
commitbab82ed05b304504e3b5d317486e152dce107313 (patch)
tree27bbabe32efe1ef35bafa1db8e52ba2f8d03ec07 /src/gpu/gl
parentdff491ba3eab17d5ae631e8c46f83a82390213b8 (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.cpp173
-rw-r--r--src/gpu/gl/GrGLShaderBuilder.cpp13
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");
}