joshualitt 2014-08-08 09:41:42 -07:00 committed by Commit bot
parent dff491ba3e
commit bab82ed05b
6 changed files with 294 additions and 3 deletions

View File

@ -36,6 +36,7 @@
'<(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',
@ -202,6 +203,7 @@
'<(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',

View File

@ -111,6 +111,7 @@
'../tests/GrDrawTargetTest.cpp',
'../tests/GrMemoryPoolTest.cpp',
'../tests/GrOrderedSetTest.cpp',
'../tests/GrGLSLPrettyPrintTest.cpp',
'../tests/GrRedBlackTreeTest.cpp',
'../tests/GrSurfaceTest.cpp',
'../tests/GrTBSearchTest.cpp',

View File

@ -0,0 +1,16 @@
/*
* 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_ */

View File

@ -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

View File

@ -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");
}

View File

@ -0,0 +1,92 @@
/*
* 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