added initial GLSL support to skslc

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2185393003

Review-Url: https://codereview.chromium.org/2185393003
This commit is contained in:
ethannicholas 2016-08-03 12:43:36 -07:00 committed by Commit bot
parent e57b8c9a79
commit f789b38935
31 changed files with 1511 additions and 451 deletions

View File

@ -459,6 +459,7 @@ test_lib("tests") {
rebase_path("tests/PathOpsSkpClipTest.cpp"), # alternate main
rebase_path("tests/RTConfRegistryTest.cpp"), # TODO: delete
rebase_path("tests/SkSLErrorTest.cpp"), # TODO: make work
rebase_path("tests/SkSLGLSLTest.cpp"), # TODO: make work
rebase_path("tests/SkpSkGrTest.cpp"), # doesn't compile
rebase_path("tests/skia_test.cpp"), # alternate main
]

View File

@ -14,6 +14,7 @@
'../src/sksl/SkSLCompiler.cpp',
'../src/sksl/SkSLIRGenerator.cpp',
'../src/sksl/SkSLParser.cpp',
'../src/sksl/SkSLGLSLCodeGenerator.cpp',
'../src/sksl/SkSLSPIRVCodeGenerator.cpp',
'../src/sksl/SkSLUtil.cpp',
'../src/sksl/ir/SkSLSymbolTable.cpp',

View File

@ -435,7 +435,7 @@ DM_SRCS_ALL = struct(
"tests/PathOpsSkpClipTest.cpp", # Alternate main.
"tests/skia_test.cpp", # Old main.
"tests/SkpSkGrTest.cpp", # Alternate main.
"tests/SkSLErrorTest.cpp", # Excluded along with Vulkan.
"tests/SkSL*.cpp", # Excluded along with Vulkan.
"tests/SVGDeviceTest.cpp",
"tools/gpu/gl/angle/*",
"tools/gpu/gl/command_buffer/*",

View File

@ -20,9 +20,9 @@ namespace SkSL {
*/
class CodeGenerator {
public:
virtual ~CodeGenerator() {}
virtual ~CodeGenerator() {}
virtual void generateCode(Program& program, std::ostream& out) = 0;
virtual void generateCode(const Program& program, std::ostream& out) = 0;
};
} // namespace

View File

@ -67,14 +67,17 @@ Compiler::Compiler()
ADD_TYPE(BVec3);
ADD_TYPE(BVec4);
ADD_TYPE(Mat2x2);
types->addWithoutOwnership("mat2x2", fContext.fMat2x2_Type.get());
ADD_TYPE(Mat2x3);
ADD_TYPE(Mat2x4);
ADD_TYPE(Mat3x2);
ADD_TYPE(Mat3x3);
types->addWithoutOwnership("mat3x3", fContext.fMat3x3_Type.get());
ADD_TYPE(Mat3x4);
ADD_TYPE(Mat4x2);
ADD_TYPE(Mat4x3);
ADD_TYPE(Mat4x4);
types->addWithoutOwnership("mat4x4", fContext.fMat4x4_Type.get());
ADD_TYPE(GenType);
ADD_TYPE(GenDType);
ADD_TYPE(GenIType);
@ -223,8 +226,7 @@ void Compiler::writeErrorCount() {
}
}
#include <fstream>
bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out) {
bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out) {
auto program = this->convertProgram(kind, text);
if (fErrorCount == 0) {
SkSL::SPIRVCodeGenerator cg(&fContext);
@ -234,13 +236,34 @@ bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out)
return fErrorCount == 0;
}
bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::string* out) {
bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::string* out) {
std::stringstream buffer;
bool result = this->toSPIRV(kind, text, buffer);
if (result) {
*out = buffer.str();
}
return result;
}
bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps,
std::ostream& out) {
auto program = this->convertProgram(kind, text);
if (fErrorCount == 0) {
SkSL::GLSLCodeGenerator cg(&fContext, caps);
cg.generateCode(*program.get(), out);
ASSERT(!out.rdstate());
}
return fErrorCount == 0;
}
bool Compiler::toGLSL(Program::Kind kind, const std::string& text, GLCaps caps,
std::string* out) {
std::stringstream buffer;
bool result = this->toGLSL(kind, text, caps, buffer);
if (result) {
*out = buffer.str();
}
return result;
}
} // namespace

View File

@ -13,6 +13,7 @@
#include "ir/SkSLSymbolTable.h"
#include "SkSLContext.h"
#include "SkSLErrorReporter.h"
#include "SkSLGLSLCodeGenerator.h"
namespace SkSL {
@ -32,9 +33,13 @@ public:
std::unique_ptr<Program> convertProgram(Program::Kind kind, std::string text);
bool toSPIRV(Program::Kind kind, std::string text, std::ostream& out);
bool toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out);
bool toSPIRV(Program::Kind kind, std::string text, std::string* out);
bool toSPIRV(Program::Kind kind, const std::string& text, std::string* out);
bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::ostream& out);
bool toGLSL(Program::Kind kind, const std::string& text, GLCaps caps, std::string* out);
void error(Position position, std::string msg) override;
@ -45,7 +50,7 @@ public:
private:
void internalConvertProgram(std::string text,
std::vector<std::unique_ptr<ProgramElement>>* result);
std::vector<std::unique_ptr<ProgramElement>>* result);
std::shared_ptr<SymbolTable> fTypes;
IRGenerator* fIRGenerator;

View File

@ -0,0 +1,479 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkSLGLSLCodeGenerator.h"
#include "string.h"
#include "GLSL.std.450.h"
#include "ir/SkSLExpressionStatement.h"
#include "ir/SkSLExtension.h"
#include "ir/SkSLIndexExpression.h"
#include "ir/SkSLVariableReference.h"
namespace SkSL {
void GLSLCodeGenerator::write(const char* s) {
if (s[0] == 0) {
return;
}
if (fAtLineStart) {
for (int i = 0; i < fIndentation; i++) {
*fOut << " ";
}
}
*fOut << s;
fAtLineStart = false;
}
void GLSLCodeGenerator::writeLine(const char* s) {
this->write(s);
*fOut << "\n";
fAtLineStart = true;
}
void GLSLCodeGenerator::write(const std::string& s) {
this->write(s.c_str());
}
void GLSLCodeGenerator::writeLine(const std::string& s) {
this->writeLine(s.c_str());
}
void GLSLCodeGenerator::writeLine() {
this->writeLine("");
}
void GLSLCodeGenerator::writeExtension(const Extension& ext) {
this->writeLine("#extension " + ext.fName + " : enable");
}
void GLSLCodeGenerator::writeType(const Type& type) {
if (type.kind() == Type::kStruct_Kind) {
for (const Type* search : fWrittenStructs) {
if (*search == type) {
// already written
this->write(type.name());
return;
}
}
fWrittenStructs.push_back(&type);
this->writeLine("struct " + type.name() + " {");
fIndentation++;
for (const auto& f : type.fields()) {
this->writeModifiers(f.fModifiers);
// sizes (which must be static in structs) are part of the type name here
this->writeType(f.fType);
this->writeLine(" " + f.fName + ";");
}
fIndentation--;
this->writeLine("}");
} else {
this->write(type.name());
}
}
void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
switch (expr.fKind) {
case Expression::kBinary_Kind:
this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
break;
case Expression::kBoolLiteral_Kind:
this->writeBoolLiteral((BoolLiteral&) expr);
break;
case Expression::kConstructor_Kind:
this->writeConstructor((Constructor&) expr);
break;
case Expression::kIntLiteral_Kind:
this->writeIntLiteral((IntLiteral&) expr);
break;
case Expression::kFieldAccess_Kind:
this->writeFieldAccess(((FieldAccess&) expr));
break;
case Expression::kFloatLiteral_Kind:
this->writeFloatLiteral(((FloatLiteral&) expr));
break;
case Expression::kFunctionCall_Kind:
this->writeFunctionCall((FunctionCall&) expr);
break;
case Expression::kPrefix_Kind:
this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
break;
case Expression::kPostfix_Kind:
this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
break;
case Expression::kSwizzle_Kind:
this->writeSwizzle((Swizzle&) expr);
break;
case Expression::kVariableReference_Kind:
this->writeVariableReference((VariableReference&) expr);
break;
case Expression::kTernary_Kind:
this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
break;
case Expression::kIndex_Kind:
this->writeIndexExpression((IndexExpression&) expr);
break;
default:
ABORT("unsupported expression: %s", expr.description().c_str());
}
}
void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
this->write(c.fFunction.fName + "(");
const char* separator = "";
for (const auto& arg : c.fArguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);
}
this->write(")");
}
void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
this->write(c.fType.name() + "(");
const char* separator = "";
for (const auto& arg : c.fArguments) {
this->write(separator);
separator = ", ";
this->writeExpression(*arg, kSequence_Precedence);
}
this->write(")");
}
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
this->write(ref.fVariable.fName);
}
void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
this->writeExpression(*expr.fBase, kPostfix_Precedence);
this->write("[");
this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
this->write("]");
}
void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
this->writeExpression(*f.fBase, kPostfix_Precedence);
this->write(".");
}
this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
}
void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
this->write(".");
for (int c : swizzle.fComponents) {
this->write(&("x\0y\0z\0w\0"[c * 2]));
}
}
static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
switch (op) {
case Token::STAR: // fall through
case Token::SLASH: // fall through
case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
case Token::PLUS: // fall through
case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
case Token::SHL: // fall through
case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
case Token::LT: // fall through
case Token::GT: // fall through
case Token::LTEQ: // fall through
case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
case Token::EQEQ: // fall through
case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
case Token::EQ: // fall through
case Token::PLUSEQ: // fall through
case Token::MINUSEQ: // fall through
case Token::STAREQ: // fall through
case Token::SLASHEQ: // fall through
case Token::PERCENTEQ: // fall through
case Token::SHLEQ: // fall through
case Token::SHREQ: // fall through
case Token::LOGICALANDEQ: // fall through
case Token::LOGICALXOREQ: // fall through
case Token::LOGICALOREQ: // fall through
case Token::BITWISEANDEQ: // fall through
case Token::BITWISEXOREQ: // fall through
case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
default: ABORT("unsupported binary operator");
}
}
void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
Precedence parentPrecedence) {
Precedence precedence = get_binary_precedence(b.fOperator);
if (precedence >= parentPrecedence) {
this->write("(");
}
this->writeExpression(*b.fLeft, precedence);
this->write(" " + Token::OperatorName(b.fOperator) + " ");
this->writeExpression(*b.fRight, precedence);
if (precedence >= parentPrecedence) {
this->write(")");
}
}
void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
Precedence parentPrecedence) {
if (kTernary_Precedence >= parentPrecedence) {
this->write("(");
}
this->writeExpression(*t.fTest, kTernary_Precedence);
this->write(" ? ");
this->writeExpression(*t.fIfTrue, kTernary_Precedence);
this->write(" : ");
this->writeExpression(*t.fIfFalse, kTernary_Precedence);
if (kTernary_Precedence >= parentPrecedence) {
this->write(")");
}
}
void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
Precedence parentPrecedence) {
if (kPrefix_Precedence >= parentPrecedence) {
this->write("(");
}
this->write(Token::OperatorName(p.fOperator));
this->writeExpression(*p.fOperand, kPrefix_Precedence);
if (kPrefix_Precedence >= parentPrecedence) {
this->write(")");
}
}
void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
Precedence parentPrecedence) {
if (kPostfix_Precedence >= parentPrecedence) {
this->write("(");
}
this->writeExpression(*p.fOperand, kPostfix_Precedence);
this->write(Token::OperatorName(p.fOperator));
if (kPostfix_Precedence >= parentPrecedence) {
this->write(")");
}
}
void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
this->write(b.fValue ? "true" : "false");
}
void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
this->write(to_string(i.fValue));
}
void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
this->write(to_string(f.fValue));
}
void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->writeType(f.fDeclaration.fReturnType);
this->write(" " + f.fDeclaration.fName + "(");
const char* separator = "";
for (const auto& param : f.fDeclaration.fParameters) {
this->write(separator);
separator = ", ";
this->writeModifiers(param->fModifiers);
this->writeType(param->fType);
this->write(" " + param->fName);
}
this->write(") ");
this->writeBlock(*f.fBody);
this->writeLine();
}
void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers) {
this->write(modifiers.description());
}
void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
if (intf.fVariable.fName == "gl_PerVertex") {
return;
}
this->writeModifiers(intf.fVariable.fModifiers);
this->writeLine(intf.fVariable.fType.name() + " {");
fIndentation++;
for (const auto& f : intf.fVariable.fType.fields()) {
this->writeModifiers(f.fModifiers);
this->writeType(f.fType);
this->writeLine(" " + f.fName + ";");
}
fIndentation--;
this->writeLine("};");
}
void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& decl) {
ASSERT(decl.fVars.size() > 0);
this->writeModifiers(decl.fVars[0]->fModifiers);
this->writeType(decl.fBaseType);
std::string separator = " ";
for (size_t i = 0; i < decl.fVars.size(); i++) {
ASSERT(decl.fVars[i]->fModifiers == decl.fVars[0]->fModifiers);
this->write(separator);
separator = ", ";
this->write(decl.fVars[i]->fName);
for (const auto& size : decl.fSizes[i]) {
this->write("[");
this->writeExpression(*size, kTopLevel_Precedence);
this->write("]");
}
if (decl.fValues[i]) {
this->write(" = ");
this->writeExpression(*decl.fValues[i], kTopLevel_Precedence);
}
}
this->write(";");
}
void GLSLCodeGenerator::writeStatement(const Statement& s) {
switch (s.fKind) {
case Statement::kBlock_Kind:
this->writeBlock((Block&) s);
break;
case Statement::kExpression_Kind:
this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
this->write(";");
break;
case Statement::kReturn_Kind:
this->writeReturnStatement((ReturnStatement&) s);
break;
case Statement::kVarDeclaration_Kind:
this->writeVarDeclaration(*((VarDeclarationStatement&) s).fDeclaration);
break;
case Statement::kIf_Kind:
this->writeIfStatement((IfStatement&) s);
break;
case Statement::kFor_Kind:
this->writeForStatement((ForStatement&) s);
break;
case Statement::kWhile_Kind:
this->writeWhileStatement((WhileStatement&) s);
break;
case Statement::kDo_Kind:
this->writeDoStatement((DoStatement&) s);
break;
case Statement::kBreak_Kind:
this->write("break;");
break;
case Statement::kContinue_Kind:
this->write("continue;");
break;
case Statement::kDiscard_Kind:
this->write("discard;");
break;
default:
ABORT("unsupported statement: %s", s.description().c_str());
}
}
void GLSLCodeGenerator::writeBlock(const Block& b) {
this->writeLine("{");
fIndentation++;
for (const auto& s : b.fStatements) {
this->writeStatement(*s);
this->writeLine();
}
fIndentation--;
this->write("}");
}
void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
this->write("if (");
this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
this->write(") ");
this->writeStatement(*stmt.fIfTrue);
if (stmt.fIfFalse) {
this->write(" else ");
this->writeStatement(*stmt.fIfFalse);
}
}
void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
this->write("for (");
if (f.fInitializer) {
this->writeStatement(*f.fInitializer);
} else {
this->write("; ");
}
if (f.fTest) {
this->writeExpression(*f.fTest, kTopLevel_Precedence);
}
this->write("; ");
if (f.fNext) {
this->writeExpression(*f.fNext, kTopLevel_Precedence);
}
this->write(") ");
this->writeStatement(*f.fStatement);
}
void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
this->write("while (");
this->writeExpression(*w.fTest, kTopLevel_Precedence);
this->write(") ");
this->writeStatement(*w.fStatement);
}
void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
this->write("do ");
this->writeStatement(*d.fStatement);
this->write(" while (");
this->writeExpression(*d.fTest, kTopLevel_Precedence);
this->write(");");
}
void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
this->write("return");
if (r.fExpression) {
this->write(" ");
this->writeExpression(*r.fExpression, kTopLevel_Precedence);
}
this->write(";");
}
void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
ASSERT(fOut == nullptr);
fOut = &out;
this->write("#version " + to_string(fCaps.fVersion));
if (fCaps.fStandard == GLCaps::kGLES_Standard) {
this->write(" es");
}
this->writeLine();
for (const auto& e : program.fElements) {
switch (e->fKind) {
case ProgramElement::kExtension_Kind:
this->writeExtension((Extension&) *e);
break;
case ProgramElement::kVar_Kind: {
VarDeclaration& decl = (VarDeclaration&) *e;
if (decl.fVars.size() > 0 && decl.fVars[0]->fModifiers.fLayout.fBuiltin == -1) {
this->writeVarDeclaration(decl);
this->writeLine();
}
break;
}
case ProgramElement::kInterfaceBlock_Kind:
this->writeInterfaceBlock((InterfaceBlock&) *e);
break;
case ProgramElement::kFunction_Kind:
this->writeFunction((FunctionDefinition&) *e);
break;
default:
printf("%s\n", e->description().c_str());
ABORT("unsupported program element");
}
}
fOut = nullptr;
}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKSL_GLSLCODEGENERATOR
#define SKSL_GLSLCODEGENERATOR
#include <stack>
#include <tuple>
#include <unordered_map>
#include "SkSLCodeGenerator.h"
#include "ir/SkSLBinaryExpression.h"
#include "ir/SkSLBoolLiteral.h"
#include "ir/SkSLConstructor.h"
#include "ir/SkSLDoStatement.h"
#include "ir/SkSLExtension.h"
#include "ir/SkSLFloatLiteral.h"
#include "ir/SkSLIfStatement.h"
#include "ir/SkSLIndexExpression.h"
#include "ir/SkSLInterfaceBlock.h"
#include "ir/SkSLIntLiteral.h"
#include "ir/SkSLFieldAccess.h"
#include "ir/SkSLForStatement.h"
#include "ir/SkSLFunctionCall.h"
#include "ir/SkSLFunctionDeclaration.h"
#include "ir/SkSLFunctionDefinition.h"
#include "ir/SkSLPrefixExpression.h"
#include "ir/SkSLPostfixExpression.h"
#include "ir/SkSLProgramElement.h"
#include "ir/SkSLReturnStatement.h"
#include "ir/SkSLStatement.h"
#include "ir/SkSLSwizzle.h"
#include "ir/SkSLTernaryExpression.h"
#include "ir/SkSLVarDeclaration.h"
#include "ir/SkSLVarDeclarationStatement.h"
#include "ir/SkSLVariableReference.h"
#include "ir/SkSLWhileStatement.h"
namespace SkSL {
#define kLast_Capability SpvCapabilityMultiViewport
struct GLCaps {
int fVersion;
enum {
kGL_Standard,
kGLES_Standard
} fStandard;
};
/**
* Converts a Program into GLSL code.
*/
class GLSLCodeGenerator : public CodeGenerator {
public:
enum Precedence {
kParentheses_Precedence = 1,
kPostfix_Precedence = 2,
kPrefix_Precedence = 3,
kMultiplicative_Precedence = 4,
kAdditive_Precedence = 5,
kShift_Precedence = 6,
kRelational_Precedence = 7,
kEquality_Precedence = 8,
kBitwiseAnd_Precedence = 9,
kBitwiseXor_Precedence = 10,
kBitwiseOr_Precedence = 11,
kLogicalAnd_Precedence = 12,
kLogicalXor_Precedence = 13,
kLogicalOr_Precedence = 14,
kTernary_Precedence = 15,
kAssignment_Precedence = 16,
kSequence_Precedence = 17,
kTopLevel_Precedence = 18
};
GLSLCodeGenerator(const Context* context, GLCaps caps)
: fContext(*context)
, fCaps(caps)
, fIndentation(0)
, fAtLineStart(true) {}
void generateCode(const Program& program, std::ostream& out) override;
private:
void write(const char* s);
void writeLine();
void writeLine(const char* s);
void write(const std::string& s);
void writeLine(const std::string& s);
void writeType(const Type& type);
void writeExtension(const Extension& ext);
void writeInterfaceBlock(const InterfaceBlock& intf);
void writeFunctionStart(const FunctionDeclaration& f);
void writeFunctionDeclaration(const FunctionDeclaration& f);
void writeFunction(const FunctionDefinition& f);
void writeLayout(const Layout& layout);
void writeModifiers(const Modifiers& modifiers);
void writeGlobalVars(const VarDeclaration& vs);
void writeVarDeclaration(const VarDeclaration& decl);
void writeVariableReference(const VariableReference& ref);
void writeExpression(const Expression& expr, Precedence parentPrecedence);
void writeIntrinsicCall(const FunctionCall& c);
void writeFunctionCall(const FunctionCall& c);
void writeConstructor(const Constructor& c);
void writeFieldAccess(const FieldAccess& f);
void writeSwizzle(const Swizzle& swizzle);
void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
void writeIndexExpression(const IndexExpression& expr);
void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
void writeBoolLiteral(const BoolLiteral& b);
void writeIntLiteral(const IntLiteral& i);
void writeFloatLiteral(const FloatLiteral& f);
void writeStatement(const Statement& s);
void writeBlock(const Block& b);
void writeIfStatement(const IfStatement& stmt);
void writeForStatement(const ForStatement& f);
void writeWhileStatement(const WhileStatement& w);
void writeDoStatement(const DoStatement& d);
void writeReturnStatement(const ReturnStatement& r);
const Context& fContext;
const GLCaps fCaps;
std::ostream* fOut;
int fIndentation;
bool fAtLineStart;
// Keeps track of which struct types we have written. Given that we are unlikely to ever write
// more than one or two structs per shader, a simple linear search will be faster than anything
// fancier.
std::vector<const Type*> fWrittenStructs;
};
}
#endif

View File

@ -182,7 +182,6 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
currentVarSizes.push_back(nullptr);
}
}
sizes.push_back(std::move(currentVarSizes));
auto var = std::unique_ptr<Variable>(new Variable(decl.fPosition, modifiers, decl.fNames[i],
*type, storage));
std::unique_ptr<Expression> value;
@ -193,12 +192,22 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
}
value = this->coerce(std::move(value), *type);
}
variables.push_back(var.get());
fSymbolTable->add(decl.fNames[i], std::move(var));
values.push_back(std::move(value));
if ("gl_FragCoord" == decl.fNames[i] && (*fSymbolTable)[decl.fNames[i]]) {
// already defined, just update the modifiers
Variable* old = (Variable*) (*fSymbolTable)[decl.fNames[i]];
old->fModifiers = var->fModifiers;
} else {
variables.push_back(var.get());
fSymbolTable->add(decl.fNames[i], std::move(var));
values.push_back(std::move(value));
sizes.push_back(std::move(currentVarSizes));
}
}
return std::unique_ptr<VarDeclaration>(new VarDeclaration(decl.fPosition, std::move(variables),
std::move(sizes), std::move(values)));
return std::unique_ptr<VarDeclaration>(new VarDeclaration(decl.fPosition,
baseType,
std::move(variables),
std::move(sizes),
std::move(values)));
}
std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
@ -573,8 +582,10 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
case Symbol::kField_Kind: {
const Field* field = (const Field*) result;
VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner);
return std::unique_ptr<Expression>(new FieldAccess(std::unique_ptr<Expression>(base),
field->fFieldIndex));
return std::unique_ptr<Expression>(new FieldAccess(
std::unique_ptr<Expression>(base),
field->fFieldIndex,
FieldAccess::kAnonymousInterfaceBlock_OwnerKind));
}
case Symbol::kType_Kind: {
const Type* t = (const Type*) result;
@ -616,6 +627,12 @@ std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr
type.description().c_str());
}
static bool is_matrix_multiply(const Type& left, const Type& right) {
if (left.kind() == Type::kMatrix_Kind) {
return right.kind() == Type::kMatrix_Kind || right.kind() == Type::kVector_Kind;
}
return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind;
}
/**
* Determines the operand and result types of a binary expression. Returns true if the expression is
* legal, false otherwise. If false, the values of the out parameters are undefined.
@ -651,18 +668,41 @@ static bool determine_binary_type(const Context& context,
right.canCoerceTo(*context.fBool_Type);
case Token::STAR: // fall through
case Token::STAREQ:
// FIXME need to handle non-square matrices
if (left.kind() == Type::kMatrix_Kind && right.kind() == Type::kVector_Kind) {
*outLeftType = &left;
*outRightType = &right;
*outResultType = &right;
return left.rows() == right.columns();
}
if (left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind) {
*outLeftType = &left;
*outRightType = &right;
*outResultType = &left;
return left.columns() == right.columns();
if (is_matrix_multiply(left, right)) {
// determine final component type
if (determine_binary_type(context, Token::STAR, left.componentType(),
right.componentType(), outLeftType, outRightType,
outResultType, false)) {
*outLeftType = &(*outResultType)->toCompound(context, left.columns(),
left.rows());;
*outRightType = &(*outResultType)->toCompound(context, right.columns(),
right.rows());;
int leftColumns = left.columns();
int leftRows = left.rows();
int rightColumns;
int rightRows;
if (right.kind() == Type::kVector_Kind) {
// matrix * vector treats the vector as a column vector, so we need to
// transpose it
rightColumns = right.rows();
rightRows = right.columns();
ASSERT(rightColumns == 1);
} else {
rightColumns = right.columns();
rightRows = right.rows();
}
if (rightColumns > 1) {
*outResultType = &(*outResultType)->toCompound(context, rightColumns,
leftRows);
} else {
// result was a column vector, transpose it back to a row
*outResultType = &(*outResultType)->toCompound(context, leftRows,
rightColumns);
}
return leftColumns == rightRows;
} else {
return false;
}
}
// fall through
default:

View File

@ -14,11 +14,26 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
#pragma clang diagnostic ignored "-Wnull-conversion"
#pragma clang diagnostic ignored "-Wsign-compare"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4018)
#endif
#include "lex.sksl.c"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#undef register
#include "ast/SkSLASTBinaryExpression.h"
@ -471,10 +486,11 @@ ASTLayout Parser::layout() {
int index = -1;
int set = -1;
int builtin = -1;
bool originUpperLeft = false;
if (this->peek().fKind == Token::LAYOUT) {
this->nextToken();
if (!this->expect(Token::LPAREN, "'('")) {
return ASTLayout(location, binding, index, set, builtin);
return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
}
for (;;) {
Token t = this->nextToken();
@ -488,6 +504,8 @@ ASTLayout Parser::layout() {
set = this->layoutInt();
} else if (t.fText == "builtin") {
builtin = this->layoutInt();
} else if (t.fText == "origin_upper_left") {
originUpperLeft = true;
} else {
this->error(t.fPosition, ("'" + t.fText +
"' is not a valid layout qualifier").c_str());
@ -501,11 +519,10 @@ ASTLayout Parser::layout() {
}
}
}
return ASTLayout(location, binding, index, set, builtin);
return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
}
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP |
MEDIUMP | HIGHP)* */
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
ASTModifiers Parser::modifiers() {
ASTLayout layout = this->layout();
int flags = 0;
@ -545,6 +562,14 @@ ASTModifiers Parser::modifiers() {
this->nextToken();
flags |= ASTModifiers::kHighp_Flag;
break;
case Token::FLAT:
this->nextToken();
flags |= ASTModifiers::kFlat_Flag;
break;
case Token::NOPERSPECTIVE:
this->nextToken();
flags |= ASTModifiers::kNoPerspective_Flag;
break;
default:
return ASTModifiers(layout, flags);
}

View File

@ -1151,7 +1151,7 @@ SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
return entry->second;
}
SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
switch (expr.fKind) {
case Expression::kBinary_Kind:
return this->writeBinaryExpression((BinaryExpression&) expr, out);
@ -1185,7 +1185,7 @@ SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
return -1;
}
SpvId SPIRVCodeGenerator::writeIntrinsicCall(FunctionCall& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) {
auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ASSERT(intrinsic != fIntrinsicMap.end());
const Type& type = c.fArguments[0]->fType;
@ -1240,7 +1240,7 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(FunctionCall& c, std::ostream& out)
}
}
SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsic kind,
SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
std::ostream& out) {
SpvId result = this->nextId();
switch (kind) {
@ -1305,7 +1305,7 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsi
return result;
}
SpvId SPIRVCodeGenerator::writeFunctionCall(FunctionCall& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) {
const auto& entry = fFunctionMap.find(&c.fFunction);
if (entry == fFunctionMap.end()) {
return this->writeIntrinsicCall(c, out);
@ -1366,7 +1366,7 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(FunctionCall& c, std::ostream& out)
return result;
}
SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
SpvId result = this->nextId();
std::vector<SpvId> arguments;
@ -1394,7 +1394,7 @@ SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
return result;
}
SpvId SPIRVCodeGenerator::writeFloatConstructor(Constructor& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) {
ASSERT(c.fType == *fContext.fFloat_Type);
ASSERT(c.fArguments.size() == 1);
ASSERT(c.fArguments[0]->fType.isNumber());
@ -1412,7 +1412,7 @@ SpvId SPIRVCodeGenerator::writeFloatConstructor(Constructor& c, std::ostream& ou
return result;
}
SpvId SPIRVCodeGenerator::writeIntConstructor(Constructor& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) {
ASSERT(c.fType == *fContext.fInt_Type);
ASSERT(c.fArguments.size() == 1);
ASSERT(c.fArguments[0]->fType.isNumber());
@ -1430,7 +1430,7 @@ SpvId SPIRVCodeGenerator::writeIntConstructor(Constructor& c, std::ostream& out)
return result;
}
SpvId SPIRVCodeGenerator::writeMatrixConstructor(Constructor& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) {
ASSERT(c.fType.kind() == Type::kMatrix_Kind);
// go ahead and write the arguments so we don't try to write new instructions in the middle of
// an instruction
@ -1502,7 +1502,7 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(Constructor& c, std::ostream& o
return result;
}
SpvId SPIRVCodeGenerator::writeVectorConstructor(Constructor& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) {
ASSERT(c.fType.kind() == Type::kVector_Kind);
if (c.isConstant()) {
return this->writeConstantVector(c);
@ -1532,7 +1532,7 @@ SpvId SPIRVCodeGenerator::writeVectorConstructor(Constructor& c, std::ostream& o
return result;
}
SpvId SPIRVCodeGenerator::writeConstructor(Constructor& c, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) {
if (c.fType == *fContext.fFloat_Type) {
return this->writeFloatConstructor(c, out);
} else if (c.fType == *fContext.fInt_Type) {
@ -1560,7 +1560,7 @@ SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
}
}
SpvStorageClass_ get_storage_class(Expression& expr) {
SpvStorageClass_ get_storage_class(const Expression& expr) {
switch (expr.fKind) {
case Expression::kVariableReference_Kind:
return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
@ -1573,7 +1573,7 @@ SpvStorageClass_ get_storage_class(Expression& expr) {
}
}
std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(Expression& expr, std::ostream& out) {
std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) {
std::vector<SpvId> chain;
switch (expr.fKind) {
case Expression::kIndex_Kind: {
@ -1697,7 +1697,7 @@ private:
const Type& fSwizzleType;
};
std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(Expression& expr,
std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
std::ostream& out) {
switch (expr.fKind) {
case Expression::kVariableReference_Kind: {
@ -1771,7 +1771,7 @@ std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(Expres
}
}
SpvId SPIRVCodeGenerator::writeVariableReference(VariableReference& ref, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) {
auto entry = fVariableMap.find(&ref.fVariable);
ASSERT(entry != fVariableMap.end());
SpvId var = entry->second;
@ -1780,15 +1780,15 @@ SpvId SPIRVCodeGenerator::writeVariableReference(VariableReference& ref, std::os
return result;
}
SpvId SPIRVCodeGenerator::writeIndexExpression(IndexExpression& expr, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) {
return getLValue(expr, out)->load(out);
}
SpvId SPIRVCodeGenerator::writeFieldAccess(FieldAccess& f, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) {
return getLValue(f, out)->load(out);
}
SpvId SPIRVCodeGenerator::writeSwizzle(Swizzle& swizzle, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) {
SpvId base = this->writeExpression(*swizzle.fBase, out);
SpvId result = this->nextId();
size_t count = swizzle.fComponents.size();
@ -1849,7 +1849,7 @@ bool is_assignment(Token::Kind op) {
}
}
SpvId SPIRVCodeGenerator::writeBinaryExpression(BinaryExpression& b, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) {
// handle cases where we don't necessarily evaluate both LHS and RHS
switch (b.fOperator) {
case Token::EQ: {
@ -2041,7 +2041,7 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(BinaryExpression& b, std::ostrea
}
}
SpvId SPIRVCodeGenerator::writeLogicalAnd(BinaryExpression& a, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) {
ASSERT(a.fOperator == Token::LOGICALAND);
BoolLiteral falseLiteral(fContext, Position(), false);
SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
@ -2062,7 +2062,7 @@ SpvId SPIRVCodeGenerator::writeLogicalAnd(BinaryExpression& a, std::ostream& out
return result;
}
SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
ASSERT(o.fOperator == Token::LOGICALOR);
BoolLiteral trueLiteral(fContext, Position(), true);
SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
@ -2083,7 +2083,7 @@ SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out)
return result;
}
SpvId SPIRVCodeGenerator::writeTernaryExpression(TernaryExpression& t, std::ostream& out) {
SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) {
SpvId test = this->writeExpression(*t.fTest, out);
if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
// both true and false are constants, can just use OpSelect
@ -2127,7 +2127,7 @@ std::unique_ptr<Expression> create_literal_1(const Context& context, const Type&
}
}
SpvId SPIRVCodeGenerator::writePrefixExpression(PrefixExpression& p, std::ostream& out) {
SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) {
if (p.fOperator == Token::MINUS) {
SpvId result = this->nextId();
SpvId typeId = this->getType(p.fType);
@ -2174,7 +2174,7 @@ SpvId SPIRVCodeGenerator::writePrefixExpression(PrefixExpression& p, std::ostrea
}
}
SpvId SPIRVCodeGenerator::writePostfixExpression(PostfixExpression& p, std::ostream& out) {
SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) {
std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
SpvId result = lv->load(out);
SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
@ -2196,7 +2196,7 @@ SpvId SPIRVCodeGenerator::writePostfixExpression(PostfixExpression& p, std::ostr
}
}
SpvId SPIRVCodeGenerator::writeBoolLiteral(BoolLiteral& b) {
SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
if (b.fValue) {
if (fBoolTrue == 0) {
fBoolTrue = this->nextId();
@ -2214,7 +2214,7 @@ SpvId SPIRVCodeGenerator::writeBoolLiteral(BoolLiteral& b) {
}
}
SpvId SPIRVCodeGenerator::writeIntLiteral(IntLiteral& i) {
SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
if (i.fType == *fContext.fInt_Type) {
auto entry = fIntConstants.find(i.fValue);
if (entry == fIntConstants.end()) {
@ -2239,7 +2239,7 @@ SpvId SPIRVCodeGenerator::writeIntLiteral(IntLiteral& i) {
}
}
SpvId SPIRVCodeGenerator::writeFloatLiteral(FloatLiteral& f) {
SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
if (f.fType == *fContext.fFloat_Type) {
float value = (float) f.fValue;
auto entry = fFloatConstants.find(value);
@ -2350,7 +2350,7 @@ void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int mem
}
}
SpvId SPIRVCodeGenerator::writeInterfaceBlock(InterfaceBlock& intf) {
SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
SpvId type = this->getType(intf.fVariable.fType);
SpvId result = this->nextId();
this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
@ -2363,7 +2363,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(InterfaceBlock& intf) {
return result;
}
void SPIRVCodeGenerator::writeGlobalVars(VarDeclaration& decl, std::ostream& out) {
void SPIRVCodeGenerator::writeGlobalVars(const VarDeclaration& decl, std::ostream& out) {
for (size_t i = 0; i < decl.fVars.size(); i++) {
if (!decl.fVars[i]->fIsReadFrom && !decl.fVars[i]->fIsWrittenTo &&
!(decl.fVars[i]->fModifiers.fFlags & (Modifiers::kIn_Flag |
@ -2399,17 +2399,17 @@ void SPIRVCodeGenerator::writeGlobalVars(VarDeclaration& decl, std::ostream& out
(SpvId) decl.fVars[i]->fType.stride(), fDecorationBuffer);
}
if (decl.fValues[i]) {
ASSERT(!fCurrentBlock);
fCurrentBlock = -1;
ASSERT(!fCurrentBlock);
fCurrentBlock = -1;
SpvId value = this->writeExpression(*decl.fValues[i], fGlobalInitializersBuffer);
this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
fCurrentBlock = 0;
fCurrentBlock = 0;
}
this->writeLayout(decl.fVars[i]->fModifiers.fLayout, id);
}
}
void SPIRVCodeGenerator::writeVarDeclaration(VarDeclaration& decl, std::ostream& out) {
void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& decl, std::ostream& out) {
for (size_t i = 0; i < decl.fVars.size(); i++) {
SpvId id = this->nextId();
fVariableMap[decl.fVars[i]] = id;
@ -2423,7 +2423,7 @@ void SPIRVCodeGenerator::writeVarDeclaration(VarDeclaration& decl, std::ostream&
}
}
void SPIRVCodeGenerator::writeStatement(Statement& s, std::ostream& out) {
void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) {
switch (s.fKind) {
case Statement::kBlock_Kind:
this->writeBlock((Block&) s, out);
@ -2457,13 +2457,13 @@ void SPIRVCodeGenerator::writeStatement(Statement& s, std::ostream& out) {
}
}
void SPIRVCodeGenerator::writeBlock(Block& b, std::ostream& out) {
void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) {
for (size_t i = 0; i < b.fStatements.size(); i++) {
this->writeStatement(*b.fStatements[i], out);
}
}
void SPIRVCodeGenerator::writeIfStatement(IfStatement& stmt, std::ostream& out) {
void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) {
SpvId test = this->writeExpression(*stmt.fTest, out);
SpvId ifTrue = this->nextId();
SpvId ifFalse = this->nextId();
@ -2494,7 +2494,7 @@ void SPIRVCodeGenerator::writeIfStatement(IfStatement& stmt, std::ostream& out)
}
}
void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) {
if (f.fInitializer) {
this->writeStatement(*f.fInitializer, out);
}
@ -2508,7 +2508,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
this->writeInstruction(SpvOpBranch, header, out);
this->writeLabel(header, out);
this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
this->writeInstruction(SpvOpBranch, start, out);
this->writeInstruction(SpvOpBranch, start, out);
this->writeLabel(start, out);
SpvId test = this->writeExpression(*f.fTest, out);
this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
@ -2527,7 +2527,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
fContinueTarget.pop();
}
void SPIRVCodeGenerator::writeReturnStatement(ReturnStatement& r, std::ostream& out) {
void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
if (r.fExpression) {
this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
out);
@ -2536,7 +2536,7 @@ void SPIRVCodeGenerator::writeReturnStatement(ReturnStatement& r, std::ostream&
}
}
void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out) {
void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) {
fGLSLExtendedInstructions = this->nextId();
std::stringstream body;
std::vector<SpvId> interfaceVars;
@ -2569,7 +2569,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
}
const FunctionDeclaration* main = nullptr;
for (auto entry : fFunctionMap) {
if (entry.first->fName == "main") {
if (entry.first->fName == "main") {
main = entry.first;
}
}
@ -2621,7 +2621,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
out << body.str();
}
void SPIRVCodeGenerator::generateCode(Program& program, std::ostream& out) {
void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) {
this->writeWord(SpvMagicNumber, out);
this->writeWord(SpvVersion, out);
this->writeWord(SKSL_MAGIC, out);

View File

@ -71,7 +71,7 @@ public:
this->setupIntrinsics();
}
void generateCode(Program& program, std::ostream& out) override;
void generateCode(const Program& program, std::ostream& out) override;
private:
enum IntrinsicKind {
@ -97,7 +97,7 @@ private:
SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
std::vector<SpvId> getAccessChain(Expression& expr, std::ostream& out);
std::vector<SpvId> getAccessChain(const Expression& expr, std::ostream& out);
void writeLayout(const Layout& layout, SpvId target);
@ -105,9 +105,9 @@ private:
void writeStruct(const Type& type, SpvId resultId);
void writeProgramElement(ProgramElement& pe, std::ostream& out);
void writeProgramElement(const ProgramElement& pe, std::ostream& out);
SpvId writeInterfaceBlock(InterfaceBlock& intf);
SpvId writeInterfaceBlock(const InterfaceBlock& intf);
SpvId writeFunctionStart(const FunctionDeclaration& f, std::ostream& out);
@ -115,78 +115,78 @@ private:
SpvId writeFunction(const FunctionDefinition& f, std::ostream& out);
void writeGlobalVars(VarDeclaration& v, std::ostream& out);
void writeGlobalVars(const VarDeclaration& v, std::ostream& out);
void writeVarDeclaration(VarDeclaration& decl, std::ostream& out);
void writeVarDeclaration(const VarDeclaration& decl, std::ostream& out);
SpvId writeVariableReference(VariableReference& ref, std::ostream& out);
SpvId writeVariableReference(const VariableReference& ref, std::ostream& out);
std::unique_ptr<LValue> getLValue(Expression& value, std::ostream& out);
std::unique_ptr<LValue> getLValue(const Expression& value, std::ostream& out);
SpvId writeExpression(Expression& expr, std::ostream& out);
SpvId writeExpression(const Expression& expr, std::ostream& out);
SpvId writeIntrinsicCall(FunctionCall& c, std::ostream& out);
SpvId writeIntrinsicCall(const FunctionCall& c, std::ostream& out);
SpvId writeFunctionCall(FunctionCall& c, std::ostream& out);
SpvId writeFunctionCall(const FunctionCall& c, std::ostream& out);
SpvId writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsic kind, std::ostream& out);
SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, std::ostream& out);
SpvId writeConstantVector(Constructor& c);
SpvId writeConstantVector(const Constructor& c);
SpvId writeFloatConstructor(Constructor& c, std::ostream& out);
SpvId writeFloatConstructor(const Constructor& c, std::ostream& out);
SpvId writeIntConstructor(Constructor& c, std::ostream& out);
SpvId writeIntConstructor(const Constructor& c, std::ostream& out);
SpvId writeMatrixConstructor(Constructor& c, std::ostream& out);
SpvId writeMatrixConstructor(const Constructor& c, std::ostream& out);
SpvId writeVectorConstructor(Constructor& c, std::ostream& out);
SpvId writeVectorConstructor(const Constructor& c, std::ostream& out);
SpvId writeConstructor(Constructor& c, std::ostream& out);
SpvId writeConstructor(const Constructor& c, std::ostream& out);
SpvId writeFieldAccess(FieldAccess& f, std::ostream& out);
SpvId writeFieldAccess(const FieldAccess& f, std::ostream& out);
SpvId writeSwizzle(Swizzle& swizzle, std::ostream& out);
SpvId writeSwizzle(const Swizzle& swizzle, std::ostream& out);
SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
SpvOp_ ifBool, std::ostream& out);
SpvId writeBinaryOperation(BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
std::ostream& out);
SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
SpvOp_ ifUInt, std::ostream& out);
SpvId writeBinaryExpression(BinaryExpression& b, std::ostream& out);
SpvId writeBinaryExpression(const BinaryExpression& b, std::ostream& out);
SpvId writeTernaryExpression(TernaryExpression& t, std::ostream& out);
SpvId writeTernaryExpression(const TernaryExpression& t, std::ostream& out);
SpvId writeIndexExpression(IndexExpression& expr, std::ostream& out);
SpvId writeIndexExpression(const IndexExpression& expr, std::ostream& out);
SpvId writeLogicalAnd(BinaryExpression& b, std::ostream& out);
SpvId writeLogicalAnd(const BinaryExpression& b, std::ostream& out);
SpvId writeLogicalOr(BinaryExpression& o, std::ostream& out);
SpvId writeLogicalOr(const BinaryExpression& o, std::ostream& out);
SpvId writePrefixExpression(PrefixExpression& p, std::ostream& out);
SpvId writePrefixExpression(const PrefixExpression& p, std::ostream& out);
SpvId writePostfixExpression(PostfixExpression& p, std::ostream& out);
SpvId writePostfixExpression(const PostfixExpression& p, std::ostream& out);
SpvId writeBoolLiteral(BoolLiteral& b);
SpvId writeBoolLiteral(const BoolLiteral& b);
SpvId writeIntLiteral(IntLiteral& i);
SpvId writeIntLiteral(const IntLiteral& i);
SpvId writeFloatLiteral(FloatLiteral& f);
SpvId writeFloatLiteral(const FloatLiteral& f);
void writeStatement(Statement& s, std::ostream& out);
void writeStatement(const Statement& s, std::ostream& out);
void writeBlock(Block& b, std::ostream& out);
void writeBlock(const Block& b, std::ostream& out);
void writeIfStatement(IfStatement& stmt, std::ostream& out);
void writeIfStatement(const IfStatement& stmt, std::ostream& out);
void writeForStatement(ForStatement& f, std::ostream& out);
void writeForStatement(const ForStatement& f, std::ostream& out);
void writeReturnStatement(ReturnStatement& r, std::ostream& out);
void writeReturnStatement(const ReturnStatement& r, std::ostream& out);
void writeCapabilities(std::ostream& out);
void writeInstructions(Program& program, std::ostream& out);
void writeInstructions(const Program& program, std::ostream& out);
void writeOpCode(SpvOp_ opCode, int length, std::ostream& out);

View File

@ -13,6 +13,10 @@
namespace SkSL {
#undef IN
#undef OUT
#undef CONST
/**
* Represents a lexical analysis token. Token is generally only used during the parse process, but
* Token::Kind is also used to represent operator kinds.
@ -89,6 +93,8 @@ struct Token {
MEDIUMP,
HIGHP,
UNIFORM,
FLAT,
NOPERSPECTIVE,
STRUCT,
LAYOUT,
DIRECTIVE,

View File

@ -8,6 +8,7 @@
#ifndef SKSL_UTIL
#define SKSL_UTIL
#include <iomanip>
#include <string>
#include <sstream>
#include "stdlib.h"
@ -19,13 +20,9 @@ namespace SkSL {
// our own definitions of certain std:: functions, because they are not always present on Android
template <typename T> std::string to_string(T value) {
#ifdef SK_BUILD_FOR_ANDROID
std::stringstream buffer;
buffer << value;
buffer << std::setprecision(std::numeric_limits<T>::digits10) << value;
return buffer.str();
#else
return std::to_string(value);
#endif
}
#if _MSC_VER

View File

@ -20,12 +20,13 @@ namespace SkSL {
*/
struct ASTLayout : public ASTNode {
// For all parameters, a -1 means no value
ASTLayout(int location, int binding, int index, int set, int builtin)
ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
: fLocation(location)
, fBinding(binding)
, fIndex(index)
, fSet(set)
, fBuiltin(builtin) {}
, fBuiltin(builtin)
, fOriginUpperLeft(originUpperLeft) {}
std::string description() const {
std::string result;
@ -50,6 +51,10 @@ struct ASTLayout : public ASTNode {
result += separator + "builtin = " + to_string(fBuiltin);
separator = ", ";
}
if (fOriginUpperLeft) {
result += separator + "origin_upper_left";
separator = ", ";
}
if (result.length() > 0) {
result = "layout (" + result + ")";
}
@ -61,6 +66,7 @@ struct ASTLayout : public ASTNode {
const int fIndex;
const int fSet;
const int fBuiltin;
const bool fOriginUpperLeft;
};
} // namespace

View File

@ -18,14 +18,16 @@ namespace SkSL {
*/
struct ASTModifiers : public ASTNode {
enum Flag {
kNo_Flag = 0,
kConst_Flag = 1,
kIn_Flag = 2,
kOut_Flag = 4,
kLowp_Flag = 8,
kMediump_Flag = 16,
kHighp_Flag = 32,
kUniform_Flag = 64
kNo_Flag = 0,
kConst_Flag = 1,
kIn_Flag = 2,
kOut_Flag = 4,
kLowp_Flag = 8,
kMediump_Flag = 16,
kHighp_Flag = 32,
kUniform_Flag = 64,
kFlat_Flag = 128,
kNoPerspective_Flag = 256
};
ASTModifiers(ASTLayout layout, int flags)
@ -49,6 +51,12 @@ struct ASTModifiers : public ASTNode {
if (fFlags & kHighp_Flag) {
result += "highp ";
}
if (fFlags & kFlat_Flag) {
result += "flat ";
}
if (fFlags & kNoPerspective_Flag) {
result += "noperspective ";
}
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
result += "inout ";

View File

@ -26,7 +26,7 @@ struct BoolLiteral : public Expression {
}
bool isConstant() const override {
return true;
return true;
}
const bool fValue;

View File

@ -17,10 +17,19 @@ namespace SkSL {
* An expression which extracts a field from a struct, as in 'foo.bar'.
*/
struct FieldAccess : public Expression {
FieldAccess(std::unique_ptr<Expression> base, int fieldIndex)
enum OwnerKind {
kDefault_OwnerKind,
// this field access is to a field of an anonymous interface block (and thus, the field name
// is actually in global scope, so only the field name needs to be written in GLSL)
kAnonymousInterfaceBlock_OwnerKind
};
FieldAccess(std::unique_ptr<Expression> base, int fieldIndex,
OwnerKind ownerKind = kDefault_OwnerKind)
: INHERITED(base->fPosition, kFieldAccess_Kind, base->fType.fields()[fieldIndex].fType)
, fBase(std::move(base))
, fFieldIndex(fieldIndex) {}
, fFieldIndex(fieldIndex)
, fOwnerKind(ownerKind) {}
virtual std::string description() const override {
return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
@ -28,6 +37,7 @@ struct FieldAccess : public Expression {
const std::unique_ptr<Expression> fBase;
const int fFieldIndex;
const OwnerKind fOwnerKind;
typedef Expression INHERITED;
};

View File

@ -26,7 +26,7 @@ struct FloatLiteral : public Expression {
}
bool isConstant() const override {
return true;
return true;
}
const double fValue;

View File

@ -24,8 +24,8 @@ struct FunctionReference : public Expression {
, fFunctions(function) {}
virtual std::string description() const override {
ASSERT(false);
return "<function>";
ASSERT(false);
return "<function>";
}
const std::vector<const FunctionDeclaration*> fFunctions;

View File

@ -27,7 +27,7 @@ struct IntLiteral : public Expression {
}
bool isConstant() const override {
return true;
return true;
}
const int64_t fValue;

View File

@ -21,14 +21,16 @@ struct Layout {
, fBinding(layout.fBinding)
, fIndex(layout.fIndex)
, fSet(layout.fSet)
, fBuiltin(layout.fBuiltin) {}
, fBuiltin(layout.fBuiltin)
, fOriginUpperLeft(layout.fOriginUpperLeft) {}
Layout(int location, int binding, int index, int set, int builtin)
Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
: fLocation(location)
, fBinding(binding)
, fIndex(index)
, fSet(set)
, fBuiltin(builtin) {}
, fBuiltin(builtin)
, fOriginUpperLeft(originUpperLeft) {}
std::string description() const {
std::string result;
@ -53,6 +55,10 @@ struct Layout {
result += separator + "builtin = " + to_string(fBuiltin);
separator = ", ";
}
if (fOriginUpperLeft) {
result += separator + "origin_upper_left";
separator = ", ";
}
if (result.length() > 0) {
result = "layout (" + result + ")";
}
@ -71,11 +77,14 @@ struct Layout {
return !(*this == other);
}
const int fLocation;
const int fBinding;
const int fIndex;
const int fSet;
const int fBuiltin;
// everything but builtin is in the GLSL spec; builtin comes from SPIR-V and identifies which
// particular builtin value this object represents.
int fLocation;
int fBinding;
int fIndex;
int fSet;
int fBuiltin;
bool fOriginUpperLeft;
};
} // namespace

View File

@ -18,14 +18,16 @@ namespace SkSL {
*/
struct Modifiers {
enum Flag {
kNo_Flag = ASTModifiers::kNo_Flag,
kConst_Flag = ASTModifiers::kConst_Flag,
kIn_Flag = ASTModifiers::kIn_Flag,
kOut_Flag = ASTModifiers::kOut_Flag,
kLowp_Flag = ASTModifiers::kLowp_Flag,
kMediump_Flag = ASTModifiers::kMediump_Flag,
kHighp_Flag = ASTModifiers::kHighp_Flag,
kUniform_Flag = ASTModifiers::kUniform_Flag
kNo_Flag = ASTModifiers::kNo_Flag,
kConst_Flag = ASTModifiers::kConst_Flag,
kIn_Flag = ASTModifiers::kIn_Flag,
kOut_Flag = ASTModifiers::kOut_Flag,
kLowp_Flag = ASTModifiers::kLowp_Flag,
kMediump_Flag = ASTModifiers::kMediump_Flag,
kHighp_Flag = ASTModifiers::kHighp_Flag,
kUniform_Flag = ASTModifiers::kUniform_Flag,
kFlat_Flag = ASTModifiers::kFlat_Flag,
kNoPerspective_Flag = ASTModifiers::kNoPerspective_Flag
};
Modifiers(const ASTModifiers& modifiers)
@ -53,6 +55,12 @@ struct Modifiers {
if (fFlags & kHighp_Flag) {
result += "highp ";
}
if (fFlags & kFlat_Flag) {
result += "flat ";
}
if (fFlags & kNoPerspective_Flag) {
result += "noperspective ";
}
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
result += "inout ";
@ -73,8 +81,8 @@ struct Modifiers {
return !(*this == other);
}
const Layout fLayout;
const int fFlags;
Layout fLayout;
int fFlags;
};
} // namespace

View File

@ -23,8 +23,8 @@ struct TypeReference : public Expression {
, fValue(type) {}
std::string description() const override {
ASSERT(false);
return "<type>";
ASSERT(false);
return "<type>";
}
const Type& fValue;

View File

@ -20,9 +20,9 @@ struct UnresolvedFunction : public Symbol {
: INHERITED(Position(), kUnresolvedFunction_Kind, funcs[0]->fName)
, fFunctions(std::move(funcs)) {
#ifdef DEBUG
for (auto func : funcs) {
ASSERT(func->fName == fName);
}
for (auto func : funcs) {
ASSERT(func->fName == fName);
}
#endif
}

View File

@ -16,14 +16,15 @@ namespace SkSL {
/**
* A variable declaration, which may consist of multiple individual variables. For instance
* 'int x, y = 1, z[4][2];' is a single VarDeclaration. This declaration would have a type of 'int',
* names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
* 'int x, y = 1, z[4][2];' is a single VarDeclaration. This declaration would have a base type of
* 'int', names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
*/
struct VarDeclaration : public ProgramElement {
VarDeclaration(Position position, std::vector<const Variable*> vars,
VarDeclaration(Position position, const Type* baseType, std::vector<const Variable*> vars,
std::vector<std::vector<std::unique_ptr<Expression>>> sizes,
std::vector<std::unique_ptr<Expression>> values)
: INHERITED(position, kVar_Kind)
, fBaseType(*baseType)
, fVars(std::move(vars))
, fSizes(std::move(sizes))
, fValues(std::move(values)) {}
@ -55,6 +56,7 @@ struct VarDeclaration : public ProgramElement {
return result;
}
const Type& fBaseType;
const std::vector<const Variable*> fVars;
const std::vector<std::vector<std::unique_ptr<Expression>>> fSizes;
const std::vector<std::unique_ptr<Expression>> fValues;

View File

@ -40,7 +40,7 @@ struct Variable : public Symbol {
return fModifiers.description() + fType.fName + " " + fName;
}
const Modifiers fModifiers;
mutable Modifiers fModifiers;
const Type& fType;
const Storage fStorage;

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,10 @@ mediump { return SkSL::Token::MEDIUMP; }
highp { return SkSL::Token::HIGHP; }
flat { return SkSL::Token::FLAT; }
noperspective { return SkSL::Token::NOPERSPECTIVE; }
struct { return SkSL::Token::STRUCT; }
layout { return SkSL::Token::LAYOUT; }

227
tests/SkSLGLSLTest.cpp Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkSLCompiler.h"
#include "Test.h"
static void test(skiatest::Reporter* r, const char* src, SkSL::GLCaps caps, const char* expected) {
SkSL::Compiler compiler;
std::string output;
bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind, src, caps, &output);
if (!result) {
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
}
REPORTER_ASSERT(r, result);
if (result) {
if (output != expected) {
SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
expected, output.c_str());
}
REPORTER_ASSERT(r, output == expected);
}
}
DEF_TEST(SkSLHelloWorld, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"out vec4 fragColor; void main() { fragColor = vec4(0.75); }",
caps,
"#version 400\n"
"out vec4 fragColor;\n"
"void main() {\n"
" fragColor = vec4(0.75);\n"
"}\n");
}
DEF_TEST(SkSLControl, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"out vec4 fragColor;"
"void main() {"
"if (1 + 2 + 3 > 5) { fragColor = vec4(0.75); } else { discard; }"
"int i = 0;"
"while (i < 10) fragColor *= 0.5;"
"do { fragColor += 0.01; } while (fragColor.x < 0.7);"
"for (int i = 0; i < 10; i++) {"
"if (i % 0 == 1) break; else continue;"
"}"
"return;"
"}",
caps,
"#version 400\n"
"out vec4 fragColor;\n"
"void main() {\n"
" if ((1 + 2) + 3 > 5) {\n"
" fragColor = vec4(0.75);\n"
" } else {\n"
" discard;\n"
" }\n"
" int i = 0;\n"
" while (i < 10) fragColor *= 0.5;\n"
" do {\n"
" fragColor += 0.01;\n"
" } while (fragColor.x < 0.7);\n"
" for (int i = 0;i < 10; i++) {\n"
" if (i % 0 == 1) break; else continue;\n"
" }\n"
" return;\n"
"}\n");
}
DEF_TEST(SkSLFunctions, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"out vec4 fragColor;"
"float foo(float v[2]) { return v[0] * v[1]; }"
"void bar(inout float x) { float y[2], z; y[0] = x; y[1] = x * 2; z = foo(y); x = z; }"
"void main() { float x = 10; bar(x); fragColor = vec4(x); }",
caps,
"#version 400\n"
"out vec4 fragColor;\n"
"float foo(in float[2] v) {\n"
" return v[0] * v[1];\n"
"}\n"
"void bar(inout float x) {\n"
" float y[2], z;\n"
" y[0] = x;\n"
" y[1] = x * 2;\n"
" z = foo(y);\n"
" x = z;\n"
"}\n"
"void main() {\n"
" float x = 10;\n"
" bar(x);\n"
" fragColor = vec4(x);\n"
"}\n");
}
DEF_TEST(SkSLOperators, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"void main() {"
"float x = 1, y = 2;"
"int z = 3;"
"x = x + y * z * x * (y - z);"
"y = x / y / z;"
"z = (z / 2 % 3 << 4) >> 2 << 1;"
"bool b = (x > 4) == x < 2 || 2 >= 5 && y <= z && 12 != 11;"
"x += 12;"
"x -= 12;"
"x *= y /= z = 10;"
"b ||= false;"
"b &&= true;"
"b ^^= false;"
"z |= 0;"
"z &= -1;"
"z ^= 0;"
"z >>= 2;"
"z <<= 4;"
"z %= 5;"
"}",
caps,
"#version 400\n"
"void main() {\n"
" float x = 1, y = 2;\n"
" int z = 3;\n"
" x = x + ((y * float(z)) * x) * (y - float(z));\n"
" y = (x / y) / float(z);\n"
" z = (((z / 2) % 3 << 4) >> 2) << 1;\n"
" bool b = x > 4 == x < 2 || (2 >= 5 && y <= float(z)) && 12 != 11;\n"
" x += 12;\n"
" x -= 12;\n"
" x *= (y /= float(z = 10));\n"
" b ||= false;\n"
" b &&= true;\n"
" b ^^= false;\n"
" z |= 0;\n"
" z &= -1;\n"
" z ^= 0;\n"
" z >>= 2;\n"
" z <<= 4;\n"
" z %= 5;\n"
"}\n");
}
DEF_TEST(SkSLMatrices, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"void main() {"
"mat2x4 x = mat2x4(1);"
"mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));"
"mat3x4 z = x * y;"
"vec3 v1 = mat3(1) * vec3(1);"
"vec3 v2 = vec3(1) * mat3(1);"
"}",
caps,
"#version 400\n"
"void main() {\n"
" mat2x4 x = mat2x4(1);\n"
" mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));\n"
" mat3x4 z = x * y;\n"
" vec3 v1 = mat3(1) * vec3(1);\n"
" vec3 v2 = vec3(1) * mat3(1);\n"
"}\n");
}
DEF_TEST(SkSLInterfaceBlock, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"uniform testBlock {"
"float x;"
"float y[2];"
"layout(binding=12) mat3x2 z;"
"bool w;"
"};"
"void main() {"
"}",
caps,
"#version 400\n"
"uniform testBlock {\n"
" float x;\n"
" float[2] y;\n"
" layout (binding = 12)mat3x2 z;\n"
" bool w;\n"
"};\n"
"void main() {\n"
"}\n");
}
DEF_TEST(SkSLStructs, r) {
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
test(r,
"struct A {"
"int x;"
"int y;"
"} a1, a2;"
"A a3;"
"struct B {"
"float x;"
"float y[2];"
"layout(binding=1) A z;"
"};"
"B b1, b2, b3;"
"void main() {"
"}",
caps,
"#version 400\n"
"struct A {\n"
" int x;\n"
" int y;\n"
"}\n"
" a1, a2;\n"
"A a3;\n"
"struct B {\n"
" float x;\n"
" float[2] y;\n"
" layout (binding = 1)A z;\n"
"}\n"
" b1, b2, b3;\n"
"void main() {\n"
"}\n");
}