'<(skia_include_path)/gpu/gl/GrGLExtensions.h',
'<(skia_include_path)/gpu/gl/GrGLFunctions.h',
'<(skia_include_path)/gpu/gl/GrGLInterface.h',
+ '<(skia_include_path)/gpu/gl/GrGLSLPrettyPrint.h',
'<(skia_src_path)/gpu/GrAAHairLinePathRenderer.cpp',
'<(skia_src_path)/gpu/GrAAHairLinePathRenderer.h',
'<(skia_src_path)/gpu/gl/GrGLPath.h',
'<(skia_src_path)/gpu/gl/GrGLPathRange.cpp',
'<(skia_src_path)/gpu/gl/GrGLPathRange.h',
+ '<(skia_src_path)/gpu/gl/GrGLSLPrettyPrint.cpp',
'<(skia_src_path)/gpu/gl/GrGLProgram.cpp',
'<(skia_src_path)/gpu/gl/GrGLProgram.h',
'<(skia_src_path)/gpu/gl/GrGLProgramDesc.cpp',
'../tests/GrDrawTargetTest.cpp',
'../tests/GrMemoryPoolTest.cpp',
'../tests/GrOrderedSetTest.cpp',
+ '../tests/GrGLSLPrettyPrintTest.cpp',
'../tests/GrRedBlackTreeTest.cpp',
'../tests/GrSurfaceTest.cpp',
'../tests/GrTBSearchTest.cpp',
--- /dev/null
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef GrGLSLPrettyPrint_DEFINED
+#define GrGLSLPrettyPrint_DEFINED
+
+#include "SkString.h"
+
+namespace GrGLSLPrettyPrint {
+ SkString PrettyPrintGLSL(const SkString& input, bool countlines);
+};
+
+#endif /* GRGLPRETTYPRINTSL_H_ */
--- /dev/null
+/*
+ * 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
#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLProgram.h"
+#include "gl/GrGLSLPrettyPrint.h"
#include "gl/GrGLUniformHandle.h"
#include "GrCoordTransform.h"
#include "GrDrawEffect.h"
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));
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!");
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");
}
--- /dev/null
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+#include "Test.h"
+#include "gl/GrGLSLPrettyPrint.h"
+
+#define ASSERT(x) REPORTER_ASSERT(r, x)
+
+const SkString input1("#this is not a realshader\nvec4 some stuff;outside of a function;"
+ "int i(int b, int c) { { some stuff;} fake block; //comments\n return i;}"
+ "void main()"
+ "{nowin a function;{indenting;{abit more;dreadedfor((;;)(;)((;;);)){doingstuff"
+ ";for(;;;){and more stufff;mixed garbage\n\n\t\t\t\t\n/*using this"
+ " comment\n is"
+ " dangerous\ndo so at your own\n risk*/;\n\n\t\t\t\n"
+ "//a comment\n}}a; little ; love; for ; leading; spaces;} "
+ "an struct = { int a; int b; };"
+ "int[5] arr = int[5](1,2,3,4,5);} some code at the bottom; for(;;) {} }");
+
+const SkString output1(
+ " 1\t#this is not a realshader\n"
+ " 2\tvec4 some stuff;\n"
+ " 3\toutside of a function;\n"
+ " 4\tint i(int b, int c) \n"
+ " 5\t{\n"
+ " 6\t\t{\n"
+ " 7\t\t\tsome stuff;\n"
+ " 8\t\t}\n"
+ " 9\t\tfake block;\n"
+ " 10\t\t//comments\n"
+ " 11\t\treturn i;\n"
+ " 12\t}\n"
+ " 13\tvoid main()\n"
+ " 14\t{\n"
+ " 15\t\tnowin a function;\n"
+ " 16\t\t{\n"
+ " 17\t\t\tindenting;\n"
+ " 18\t\t\t{\n"
+ " 19\t\t\t\tabit more;\n"
+ " 20\t\t\t\tdreadedfor((;;)(;)((;;);))\n"
+ " 21\t\t\t\t{\n"
+ " 22\t\t\t\t\tdoingstuff;\n"
+ " 23\t\t\t\t\tfor(;;;)\n"
+ " 24\t\t\t\t\t{\n"
+ " 25\t\t\t\t\t\tand more stufff;\n"
+ " 26\t\t\t\t\t\tmixed garbage/*using this comment\n"
+ " 27\t\t\t\t\t\t is dangerous\n"
+ " 28\t\t\t\t\t\tdo so at your own\n"
+ " 29\t\t\t\t\t\t risk*/;\n"
+ " 30\t\t\t\t\t\t//a comment\n"
+ " 31\t\t\t\t\t}\n"
+ " 32\t\t\t\t}\n"
+ " 33\t\t\t\ta;\n"
+ " 34\t\t\t\tlittle ;\n"
+ " 35\t\t\t\tlove;\n"
+ " 36\t\t\t\tfor ;\n"
+ " 37\t\t\t\tleading;\n"
+ " 38\t\t\t\tspaces;\n"
+ " 39\t\t\t}\n"
+ " 40\t\t\tan struct = \n"
+ " 41\t\t\t{\n"
+ " 42\t\t\t\tint a;\n"
+ " 43\t\t\t\tint b;\n"
+ " 44\t\t\t}\n"
+ " 45\t\t\t;\n"
+ " 46\t\t\tint[5] arr = int[5](1,2,3,4,5);\n"
+ " 47\t\t}\n"
+ " 48\t\tsome code at the bottom;\n"
+ " 49\t\tfor(;;) \n"
+ " 50\t\t{\n"
+ " 51\t\t}\n"
+ " 52\t}\n"
+ " 53\t");
+
+const SkString input2("{;;{{{{;;;{{{{{{{{{{{###\n##\n#####(((((((((((((unbalanced verything;;;"
+ "}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"
+ ";;;;;;/////");
+
+DEF_TEST(GrGLSLPrettyPrint, r) {
+ SkString test = GrGLSLPrettyPrint::PrettyPrintGLSL(input1, true);
+ ASSERT(output1 == test);
+
+ // Just test we don't crash with garbage input
+ ASSERT(GrGLSLPrettyPrint::PrettyPrintGLSL(input2, true).c_str() != NULL);
+}
+
+#endif