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:
parent
e57b8c9a79
commit
f789b38935
1
BUILD.gn
1
BUILD.gn
@ -459,6 +459,7 @@ test_lib("tests") {
|
|||||||
rebase_path("tests/PathOpsSkpClipTest.cpp"), # alternate main
|
rebase_path("tests/PathOpsSkpClipTest.cpp"), # alternate main
|
||||||
rebase_path("tests/RTConfRegistryTest.cpp"), # TODO: delete
|
rebase_path("tests/RTConfRegistryTest.cpp"), # TODO: delete
|
||||||
rebase_path("tests/SkSLErrorTest.cpp"), # TODO: make work
|
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/SkpSkGrTest.cpp"), # doesn't compile
|
||||||
rebase_path("tests/skia_test.cpp"), # alternate main
|
rebase_path("tests/skia_test.cpp"), # alternate main
|
||||||
]
|
]
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
'../src/sksl/SkSLCompiler.cpp',
|
'../src/sksl/SkSLCompiler.cpp',
|
||||||
'../src/sksl/SkSLIRGenerator.cpp',
|
'../src/sksl/SkSLIRGenerator.cpp',
|
||||||
'../src/sksl/SkSLParser.cpp',
|
'../src/sksl/SkSLParser.cpp',
|
||||||
|
'../src/sksl/SkSLGLSLCodeGenerator.cpp',
|
||||||
'../src/sksl/SkSLSPIRVCodeGenerator.cpp',
|
'../src/sksl/SkSLSPIRVCodeGenerator.cpp',
|
||||||
'../src/sksl/SkSLUtil.cpp',
|
'../src/sksl/SkSLUtil.cpp',
|
||||||
'../src/sksl/ir/SkSLSymbolTable.cpp',
|
'../src/sksl/ir/SkSLSymbolTable.cpp',
|
||||||
|
@ -435,7 +435,7 @@ DM_SRCS_ALL = struct(
|
|||||||
"tests/PathOpsSkpClipTest.cpp", # Alternate main.
|
"tests/PathOpsSkpClipTest.cpp", # Alternate main.
|
||||||
"tests/skia_test.cpp", # Old main.
|
"tests/skia_test.cpp", # Old main.
|
||||||
"tests/SkpSkGrTest.cpp", # Alternate main.
|
"tests/SkpSkGrTest.cpp", # Alternate main.
|
||||||
"tests/SkSLErrorTest.cpp", # Excluded along with Vulkan.
|
"tests/SkSL*.cpp", # Excluded along with Vulkan.
|
||||||
"tests/SVGDeviceTest.cpp",
|
"tests/SVGDeviceTest.cpp",
|
||||||
"tools/gpu/gl/angle/*",
|
"tools/gpu/gl/angle/*",
|
||||||
"tools/gpu/gl/command_buffer/*",
|
"tools/gpu/gl/command_buffer/*",
|
||||||
|
@ -20,9 +20,9 @@ namespace SkSL {
|
|||||||
*/
|
*/
|
||||||
class CodeGenerator {
|
class CodeGenerator {
|
||||||
public:
|
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
|
} // namespace
|
||||||
|
@ -67,14 +67,17 @@ Compiler::Compiler()
|
|||||||
ADD_TYPE(BVec3);
|
ADD_TYPE(BVec3);
|
||||||
ADD_TYPE(BVec4);
|
ADD_TYPE(BVec4);
|
||||||
ADD_TYPE(Mat2x2);
|
ADD_TYPE(Mat2x2);
|
||||||
|
types->addWithoutOwnership("mat2x2", fContext.fMat2x2_Type.get());
|
||||||
ADD_TYPE(Mat2x3);
|
ADD_TYPE(Mat2x3);
|
||||||
ADD_TYPE(Mat2x4);
|
ADD_TYPE(Mat2x4);
|
||||||
ADD_TYPE(Mat3x2);
|
ADD_TYPE(Mat3x2);
|
||||||
ADD_TYPE(Mat3x3);
|
ADD_TYPE(Mat3x3);
|
||||||
|
types->addWithoutOwnership("mat3x3", fContext.fMat3x3_Type.get());
|
||||||
ADD_TYPE(Mat3x4);
|
ADD_TYPE(Mat3x4);
|
||||||
ADD_TYPE(Mat4x2);
|
ADD_TYPE(Mat4x2);
|
||||||
ADD_TYPE(Mat4x3);
|
ADD_TYPE(Mat4x3);
|
||||||
ADD_TYPE(Mat4x4);
|
ADD_TYPE(Mat4x4);
|
||||||
|
types->addWithoutOwnership("mat4x4", fContext.fMat4x4_Type.get());
|
||||||
ADD_TYPE(GenType);
|
ADD_TYPE(GenType);
|
||||||
ADD_TYPE(GenDType);
|
ADD_TYPE(GenDType);
|
||||||
ADD_TYPE(GenIType);
|
ADD_TYPE(GenIType);
|
||||||
@ -223,8 +226,7 @@ void Compiler::writeErrorCount() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <fstream>
|
bool Compiler::toSPIRV(Program::Kind kind, const std::string& text, std::ostream& out) {
|
||||||
bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out) {
|
|
||||||
auto program = this->convertProgram(kind, text);
|
auto program = this->convertProgram(kind, text);
|
||||||
if (fErrorCount == 0) {
|
if (fErrorCount == 0) {
|
||||||
SkSL::SPIRVCodeGenerator cg(&fContext);
|
SkSL::SPIRVCodeGenerator cg(&fContext);
|
||||||
@ -234,13 +236,34 @@ bool Compiler::toSPIRV(Program::Kind kind, std::string text, std::ostream& out)
|
|||||||
return fErrorCount == 0;
|
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;
|
std::stringstream buffer;
|
||||||
bool result = this->toSPIRV(kind, text, buffer);
|
bool result = this->toSPIRV(kind, text, buffer);
|
||||||
if (result) {
|
if (result) {
|
||||||
*out = buffer.str();
|
*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;
|
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
|
} // namespace
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "ir/SkSLSymbolTable.h"
|
#include "ir/SkSLSymbolTable.h"
|
||||||
#include "SkSLContext.h"
|
#include "SkSLContext.h"
|
||||||
#include "SkSLErrorReporter.h"
|
#include "SkSLErrorReporter.h"
|
||||||
|
#include "SkSLGLSLCodeGenerator.h"
|
||||||
|
|
||||||
namespace SkSL {
|
namespace SkSL {
|
||||||
|
|
||||||
@ -32,9 +33,13 @@ public:
|
|||||||
|
|
||||||
std::unique_ptr<Program> convertProgram(Program::Kind kind, std::string text);
|
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;
|
void error(Position position, std::string msg) override;
|
||||||
|
|
||||||
@ -45,7 +50,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void internalConvertProgram(std::string text,
|
void internalConvertProgram(std::string text,
|
||||||
std::vector<std::unique_ptr<ProgramElement>>* result);
|
std::vector<std::unique_ptr<ProgramElement>>* result);
|
||||||
|
|
||||||
std::shared_ptr<SymbolTable> fTypes;
|
std::shared_ptr<SymbolTable> fTypes;
|
||||||
IRGenerator* fIRGenerator;
|
IRGenerator* fIRGenerator;
|
||||||
|
479
src/sksl/SkSLGLSLCodeGenerator.cpp
Normal file
479
src/sksl/SkSLGLSLCodeGenerator.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
177
src/sksl/SkSLGLSLCodeGenerator.h
Normal file
177
src/sksl/SkSLGLSLCodeGenerator.h
Normal 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
|
@ -182,7 +182,6 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
|
|||||||
currentVarSizes.push_back(nullptr);
|
currentVarSizes.push_back(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sizes.push_back(std::move(currentVarSizes));
|
|
||||||
auto var = std::unique_ptr<Variable>(new Variable(decl.fPosition, modifiers, decl.fNames[i],
|
auto var = std::unique_ptr<Variable>(new Variable(decl.fPosition, modifiers, decl.fNames[i],
|
||||||
*type, storage));
|
*type, storage));
|
||||||
std::unique_ptr<Expression> value;
|
std::unique_ptr<Expression> value;
|
||||||
@ -193,12 +192,22 @@ std::unique_ptr<VarDeclaration> IRGenerator::convertVarDeclaration(const ASTVarD
|
|||||||
}
|
}
|
||||||
value = this->coerce(std::move(value), *type);
|
value = this->coerce(std::move(value), *type);
|
||||||
}
|
}
|
||||||
variables.push_back(var.get());
|
if ("gl_FragCoord" == decl.fNames[i] && (*fSymbolTable)[decl.fNames[i]]) {
|
||||||
fSymbolTable->add(decl.fNames[i], std::move(var));
|
// already defined, just update the modifiers
|
||||||
values.push_back(std::move(value));
|
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),
|
return std::unique_ptr<VarDeclaration>(new VarDeclaration(decl.fPosition,
|
||||||
std::move(sizes), std::move(values)));
|
baseType,
|
||||||
|
std::move(variables),
|
||||||
|
std::move(sizes),
|
||||||
|
std::move(values)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
|
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: {
|
case Symbol::kField_Kind: {
|
||||||
const Field* field = (const Field*) result;
|
const Field* field = (const Field*) result;
|
||||||
VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner);
|
VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner);
|
||||||
return std::unique_ptr<Expression>(new FieldAccess(std::unique_ptr<Expression>(base),
|
return std::unique_ptr<Expression>(new FieldAccess(
|
||||||
field->fFieldIndex));
|
std::unique_ptr<Expression>(base),
|
||||||
|
field->fFieldIndex,
|
||||||
|
FieldAccess::kAnonymousInterfaceBlock_OwnerKind));
|
||||||
}
|
}
|
||||||
case Symbol::kType_Kind: {
|
case Symbol::kType_Kind: {
|
||||||
const Type* t = (const Type*) result;
|
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());
|
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
|
* 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.
|
* 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);
|
right.canCoerceTo(*context.fBool_Type);
|
||||||
case Token::STAR: // fall through
|
case Token::STAR: // fall through
|
||||||
case Token::STAREQ:
|
case Token::STAREQ:
|
||||||
// FIXME need to handle non-square matrices
|
if (is_matrix_multiply(left, right)) {
|
||||||
if (left.kind() == Type::kMatrix_Kind && right.kind() == Type::kVector_Kind) {
|
// determine final component type
|
||||||
*outLeftType = &left;
|
if (determine_binary_type(context, Token::STAR, left.componentType(),
|
||||||
*outRightType = &right;
|
right.componentType(), outLeftType, outRightType,
|
||||||
*outResultType = &right;
|
outResultType, false)) {
|
||||||
return left.rows() == right.columns();
|
*outLeftType = &(*outResultType)->toCompound(context, left.columns(),
|
||||||
}
|
left.rows());;
|
||||||
if (left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind) {
|
*outRightType = &(*outResultType)->toCompound(context, right.columns(),
|
||||||
*outLeftType = &left;
|
right.rows());;
|
||||||
*outRightType = &right;
|
int leftColumns = left.columns();
|
||||||
*outResultType = &left;
|
int leftRows = left.rows();
|
||||||
return left.columns() == right.columns();
|
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
|
// fall through
|
||||||
default:
|
default:
|
||||||
|
@ -14,11 +14,26 @@
|
|||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
|
#pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
|
||||||
#pragma clang diagnostic ignored "-Wnull-conversion"
|
#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
|
#endif
|
||||||
#include "lex.sksl.c"
|
#include "lex.sksl.c"
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
#undef register
|
#undef register
|
||||||
|
|
||||||
#include "ast/SkSLASTBinaryExpression.h"
|
#include "ast/SkSLASTBinaryExpression.h"
|
||||||
@ -471,10 +486,11 @@ ASTLayout Parser::layout() {
|
|||||||
int index = -1;
|
int index = -1;
|
||||||
int set = -1;
|
int set = -1;
|
||||||
int builtin = -1;
|
int builtin = -1;
|
||||||
|
bool originUpperLeft = false;
|
||||||
if (this->peek().fKind == Token::LAYOUT) {
|
if (this->peek().fKind == Token::LAYOUT) {
|
||||||
this->nextToken();
|
this->nextToken();
|
||||||
if (!this->expect(Token::LPAREN, "'('")) {
|
if (!this->expect(Token::LPAREN, "'('")) {
|
||||||
return ASTLayout(location, binding, index, set, builtin);
|
return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Token t = this->nextToken();
|
Token t = this->nextToken();
|
||||||
@ -488,6 +504,8 @@ ASTLayout Parser::layout() {
|
|||||||
set = this->layoutInt();
|
set = this->layoutInt();
|
||||||
} else if (t.fText == "builtin") {
|
} else if (t.fText == "builtin") {
|
||||||
builtin = this->layoutInt();
|
builtin = this->layoutInt();
|
||||||
|
} else if (t.fText == "origin_upper_left") {
|
||||||
|
originUpperLeft = true;
|
||||||
} else {
|
} else {
|
||||||
this->error(t.fPosition, ("'" + t.fText +
|
this->error(t.fPosition, ("'" + t.fText +
|
||||||
"' is not a valid layout qualifier").c_str());
|
"' 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 |
|
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
|
||||||
MEDIUMP | HIGHP)* */
|
|
||||||
ASTModifiers Parser::modifiers() {
|
ASTModifiers Parser::modifiers() {
|
||||||
ASTLayout layout = this->layout();
|
ASTLayout layout = this->layout();
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
@ -545,6 +562,14 @@ ASTModifiers Parser::modifiers() {
|
|||||||
this->nextToken();
|
this->nextToken();
|
||||||
flags |= ASTModifiers::kHighp_Flag;
|
flags |= ASTModifiers::kHighp_Flag;
|
||||||
break;
|
break;
|
||||||
|
case Token::FLAT:
|
||||||
|
this->nextToken();
|
||||||
|
flags |= ASTModifiers::kFlat_Flag;
|
||||||
|
break;
|
||||||
|
case Token::NOPERSPECTIVE:
|
||||||
|
this->nextToken();
|
||||||
|
flags |= ASTModifiers::kNoPerspective_Flag;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return ASTModifiers(layout, flags);
|
return ASTModifiers(layout, flags);
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1151,7 @@ SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
|
|||||||
return entry->second;
|
return entry->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
|
SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
|
||||||
switch (expr.fKind) {
|
switch (expr.fKind) {
|
||||||
case Expression::kBinary_Kind:
|
case Expression::kBinary_Kind:
|
||||||
return this->writeBinaryExpression((BinaryExpression&) expr, out);
|
return this->writeBinaryExpression((BinaryExpression&) expr, out);
|
||||||
@ -1185,7 +1185,7 @@ SpvId SPIRVCodeGenerator::writeExpression(Expression& expr, std::ostream& out) {
|
|||||||
return -1;
|
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);
|
auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
|
||||||
ASSERT(intrinsic != fIntrinsicMap.end());
|
ASSERT(intrinsic != fIntrinsicMap.end());
|
||||||
const Type& type = c.fArguments[0]->fType;
|
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) {
|
std::ostream& out) {
|
||||||
SpvId result = this->nextId();
|
SpvId result = this->nextId();
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@ -1305,7 +1305,7 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(FunctionCall& c, SpecialIntrinsi
|
|||||||
return result;
|
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);
|
const auto& entry = fFunctionMap.find(&c.fFunction);
|
||||||
if (entry == fFunctionMap.end()) {
|
if (entry == fFunctionMap.end()) {
|
||||||
return this->writeIntrinsicCall(c, out);
|
return this->writeIntrinsicCall(c, out);
|
||||||
@ -1366,7 +1366,7 @@ SpvId SPIRVCodeGenerator::writeFunctionCall(FunctionCall& c, std::ostream& out)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
|
SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
|
||||||
ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
|
ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
|
||||||
SpvId result = this->nextId();
|
SpvId result = this->nextId();
|
||||||
std::vector<SpvId> arguments;
|
std::vector<SpvId> arguments;
|
||||||
@ -1394,7 +1394,7 @@ SpvId SPIRVCodeGenerator::writeConstantVector(Constructor& c) {
|
|||||||
return result;
|
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.fType == *fContext.fFloat_Type);
|
||||||
ASSERT(c.fArguments.size() == 1);
|
ASSERT(c.fArguments.size() == 1);
|
||||||
ASSERT(c.fArguments[0]->fType.isNumber());
|
ASSERT(c.fArguments[0]->fType.isNumber());
|
||||||
@ -1412,7 +1412,7 @@ SpvId SPIRVCodeGenerator::writeFloatConstructor(Constructor& c, std::ostream& ou
|
|||||||
return result;
|
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.fType == *fContext.fInt_Type);
|
||||||
ASSERT(c.fArguments.size() == 1);
|
ASSERT(c.fArguments.size() == 1);
|
||||||
ASSERT(c.fArguments[0]->fType.isNumber());
|
ASSERT(c.fArguments[0]->fType.isNumber());
|
||||||
@ -1430,7 +1430,7 @@ SpvId SPIRVCodeGenerator::writeIntConstructor(Constructor& c, std::ostream& out)
|
|||||||
return result;
|
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);
|
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
|
// go ahead and write the arguments so we don't try to write new instructions in the middle of
|
||||||
// an instruction
|
// an instruction
|
||||||
@ -1502,7 +1502,7 @@ SpvId SPIRVCodeGenerator::writeMatrixConstructor(Constructor& c, std::ostream& o
|
|||||||
return result;
|
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);
|
ASSERT(c.fType.kind() == Type::kVector_Kind);
|
||||||
if (c.isConstant()) {
|
if (c.isConstant()) {
|
||||||
return this->writeConstantVector(c);
|
return this->writeConstantVector(c);
|
||||||
@ -1532,7 +1532,7 @@ SpvId SPIRVCodeGenerator::writeVectorConstructor(Constructor& c, std::ostream& o
|
|||||||
return result;
|
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) {
|
if (c.fType == *fContext.fFloat_Type) {
|
||||||
return this->writeFloatConstructor(c, out);
|
return this->writeFloatConstructor(c, out);
|
||||||
} else if (c.fType == *fContext.fInt_Type) {
|
} 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) {
|
switch (expr.fKind) {
|
||||||
case Expression::kVariableReference_Kind:
|
case Expression::kVariableReference_Kind:
|
||||||
return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
|
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;
|
std::vector<SpvId> chain;
|
||||||
switch (expr.fKind) {
|
switch (expr.fKind) {
|
||||||
case Expression::kIndex_Kind: {
|
case Expression::kIndex_Kind: {
|
||||||
@ -1697,7 +1697,7 @@ private:
|
|||||||
const Type& fSwizzleType;
|
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) {
|
std::ostream& out) {
|
||||||
switch (expr.fKind) {
|
switch (expr.fKind) {
|
||||||
case Expression::kVariableReference_Kind: {
|
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);
|
auto entry = fVariableMap.find(&ref.fVariable);
|
||||||
ASSERT(entry != fVariableMap.end());
|
ASSERT(entry != fVariableMap.end());
|
||||||
SpvId var = entry->second;
|
SpvId var = entry->second;
|
||||||
@ -1780,15 +1780,15 @@ SpvId SPIRVCodeGenerator::writeVariableReference(VariableReference& ref, std::os
|
|||||||
return result;
|
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);
|
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);
|
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 base = this->writeExpression(*swizzle.fBase, out);
|
||||||
SpvId result = this->nextId();
|
SpvId result = this->nextId();
|
||||||
size_t count = swizzle.fComponents.size();
|
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
|
// handle cases where we don't necessarily evaluate both LHS and RHS
|
||||||
switch (b.fOperator) {
|
switch (b.fOperator) {
|
||||||
case Token::EQ: {
|
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);
|
ASSERT(a.fOperator == Token::LOGICALAND);
|
||||||
BoolLiteral falseLiteral(fContext, Position(), false);
|
BoolLiteral falseLiteral(fContext, Position(), false);
|
||||||
SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
|
SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
|
||||||
@ -2062,7 +2062,7 @@ SpvId SPIRVCodeGenerator::writeLogicalAnd(BinaryExpression& a, std::ostream& out
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out) {
|
SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
|
||||||
ASSERT(o.fOperator == Token::LOGICALOR);
|
ASSERT(o.fOperator == Token::LOGICALOR);
|
||||||
BoolLiteral trueLiteral(fContext, Position(), true);
|
BoolLiteral trueLiteral(fContext, Position(), true);
|
||||||
SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
|
SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
|
||||||
@ -2083,7 +2083,7 @@ SpvId SPIRVCodeGenerator::writeLogicalOr(BinaryExpression& o, std::ostream& out)
|
|||||||
return result;
|
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);
|
SpvId test = this->writeExpression(*t.fTest, out);
|
||||||
if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
|
if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
|
||||||
// both true and false are constants, can just use OpSelect
|
// 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) {
|
if (p.fOperator == Token::MINUS) {
|
||||||
SpvId result = this->nextId();
|
SpvId result = this->nextId();
|
||||||
SpvId typeId = this->getType(p.fType);
|
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);
|
std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
|
||||||
SpvId result = lv->load(out);
|
SpvId result = lv->load(out);
|
||||||
SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), 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 (b.fValue) {
|
||||||
if (fBoolTrue == 0) {
|
if (fBoolTrue == 0) {
|
||||||
fBoolTrue = this->nextId();
|
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) {
|
if (i.fType == *fContext.fInt_Type) {
|
||||||
auto entry = fIntConstants.find(i.fValue);
|
auto entry = fIntConstants.find(i.fValue);
|
||||||
if (entry == fIntConstants.end()) {
|
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) {
|
if (f.fType == *fContext.fFloat_Type) {
|
||||||
float value = (float) f.fValue;
|
float value = (float) f.fValue;
|
||||||
auto entry = fFloatConstants.find(value);
|
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 type = this->getType(intf.fVariable.fType);
|
||||||
SpvId result = this->nextId();
|
SpvId result = this->nextId();
|
||||||
this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
|
this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
|
||||||
@ -2363,7 +2363,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(InterfaceBlock& intf) {
|
|||||||
return result;
|
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++) {
|
for (size_t i = 0; i < decl.fVars.size(); i++) {
|
||||||
if (!decl.fVars[i]->fIsReadFrom && !decl.fVars[i]->fIsWrittenTo &&
|
if (!decl.fVars[i]->fIsReadFrom && !decl.fVars[i]->fIsWrittenTo &&
|
||||||
!(decl.fVars[i]->fModifiers.fFlags & (Modifiers::kIn_Flag |
|
!(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);
|
(SpvId) decl.fVars[i]->fType.stride(), fDecorationBuffer);
|
||||||
}
|
}
|
||||||
if (decl.fValues[i]) {
|
if (decl.fValues[i]) {
|
||||||
ASSERT(!fCurrentBlock);
|
ASSERT(!fCurrentBlock);
|
||||||
fCurrentBlock = -1;
|
fCurrentBlock = -1;
|
||||||
SpvId value = this->writeExpression(*decl.fValues[i], fGlobalInitializersBuffer);
|
SpvId value = this->writeExpression(*decl.fValues[i], fGlobalInitializersBuffer);
|
||||||
this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
|
this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
|
||||||
fCurrentBlock = 0;
|
fCurrentBlock = 0;
|
||||||
}
|
}
|
||||||
this->writeLayout(decl.fVars[i]->fModifiers.fLayout, id);
|
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++) {
|
for (size_t i = 0; i < decl.fVars.size(); i++) {
|
||||||
SpvId id = this->nextId();
|
SpvId id = this->nextId();
|
||||||
fVariableMap[decl.fVars[i]] = id;
|
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) {
|
switch (s.fKind) {
|
||||||
case Statement::kBlock_Kind:
|
case Statement::kBlock_Kind:
|
||||||
this->writeBlock((Block&) s, out);
|
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++) {
|
for (size_t i = 0; i < b.fStatements.size(); i++) {
|
||||||
this->writeStatement(*b.fStatements[i], out);
|
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 test = this->writeExpression(*stmt.fTest, out);
|
||||||
SpvId ifTrue = this->nextId();
|
SpvId ifTrue = this->nextId();
|
||||||
SpvId ifFalse = 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) {
|
if (f.fInitializer) {
|
||||||
this->writeStatement(*f.fInitializer, out);
|
this->writeStatement(*f.fInitializer, out);
|
||||||
}
|
}
|
||||||
@ -2508,7 +2508,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
|
|||||||
this->writeInstruction(SpvOpBranch, header, out);
|
this->writeInstruction(SpvOpBranch, header, out);
|
||||||
this->writeLabel(header, out);
|
this->writeLabel(header, out);
|
||||||
this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
|
this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
|
||||||
this->writeInstruction(SpvOpBranch, start, out);
|
this->writeInstruction(SpvOpBranch, start, out);
|
||||||
this->writeLabel(start, out);
|
this->writeLabel(start, out);
|
||||||
SpvId test = this->writeExpression(*f.fTest, out);
|
SpvId test = this->writeExpression(*f.fTest, out);
|
||||||
this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
|
this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
|
||||||
@ -2527,7 +2527,7 @@ void SPIRVCodeGenerator::writeForStatement(ForStatement& f, std::ostream& out) {
|
|||||||
fContinueTarget.pop();
|
fContinueTarget.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPIRVCodeGenerator::writeReturnStatement(ReturnStatement& r, std::ostream& out) {
|
void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
|
||||||
if (r.fExpression) {
|
if (r.fExpression) {
|
||||||
this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
|
this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
|
||||||
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();
|
fGLSLExtendedInstructions = this->nextId();
|
||||||
std::stringstream body;
|
std::stringstream body;
|
||||||
std::vector<SpvId> interfaceVars;
|
std::vector<SpvId> interfaceVars;
|
||||||
@ -2569,7 +2569,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
|
|||||||
}
|
}
|
||||||
const FunctionDeclaration* main = nullptr;
|
const FunctionDeclaration* main = nullptr;
|
||||||
for (auto entry : fFunctionMap) {
|
for (auto entry : fFunctionMap) {
|
||||||
if (entry.first->fName == "main") {
|
if (entry.first->fName == "main") {
|
||||||
main = entry.first;
|
main = entry.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2621,7 +2621,7 @@ void SPIRVCodeGenerator::writeInstructions(Program& program, std::ostream& out)
|
|||||||
out << body.str();
|
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(SpvMagicNumber, out);
|
||||||
this->writeWord(SpvVersion, out);
|
this->writeWord(SpvVersion, out);
|
||||||
this->writeWord(SKSL_MAGIC, out);
|
this->writeWord(SKSL_MAGIC, out);
|
||||||
|
@ -71,7 +71,7 @@ public:
|
|||||||
this->setupIntrinsics();
|
this->setupIntrinsics();
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateCode(Program& program, std::ostream& out) override;
|
void generateCode(const Program& program, std::ostream& out) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum IntrinsicKind {
|
enum IntrinsicKind {
|
||||||
@ -97,7 +97,7 @@ private:
|
|||||||
|
|
||||||
SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
|
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);
|
void writeLayout(const Layout& layout, SpvId target);
|
||||||
|
|
||||||
@ -105,9 +105,9 @@ private:
|
|||||||
|
|
||||||
void writeStruct(const Type& type, SpvId resultId);
|
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);
|
SpvId writeFunctionStart(const FunctionDeclaration& f, std::ostream& out);
|
||||||
|
|
||||||
@ -115,78 +115,78 @@ private:
|
|||||||
|
|
||||||
SpvId writeFunction(const FunctionDefinition& f, std::ostream& out);
|
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 writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
|
||||||
SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
|
SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
|
||||||
SpvOp_ ifBool, std::ostream& out);
|
SpvOp_ ifBool, std::ostream& out);
|
||||||
|
|
||||||
SpvId writeBinaryOperation(BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
|
SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
|
||||||
std::ostream& out);
|
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 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);
|
void writeOpCode(SpvOp_ opCode, int length, std::ostream& out);
|
||||||
|
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
namespace SkSL {
|
namespace SkSL {
|
||||||
|
|
||||||
|
#undef IN
|
||||||
|
#undef OUT
|
||||||
|
#undef CONST
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a lexical analysis token. Token is generally only used during the parse process, but
|
* Represents a lexical analysis token. Token is generally only used during the parse process, but
|
||||||
* Token::Kind is also used to represent operator kinds.
|
* Token::Kind is also used to represent operator kinds.
|
||||||
@ -89,6 +93,8 @@ struct Token {
|
|||||||
MEDIUMP,
|
MEDIUMP,
|
||||||
HIGHP,
|
HIGHP,
|
||||||
UNIFORM,
|
UNIFORM,
|
||||||
|
FLAT,
|
||||||
|
NOPERSPECTIVE,
|
||||||
STRUCT,
|
STRUCT,
|
||||||
LAYOUT,
|
LAYOUT,
|
||||||
DIRECTIVE,
|
DIRECTIVE,
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef SKSL_UTIL
|
#ifndef SKSL_UTIL
|
||||||
#define SKSL_UTIL
|
#define SKSL_UTIL
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
@ -19,13 +20,9 @@ namespace SkSL {
|
|||||||
// our own definitions of certain std:: functions, because they are not always present on Android
|
// our own definitions of certain std:: functions, because they are not always present on Android
|
||||||
|
|
||||||
template <typename T> std::string to_string(T value) {
|
template <typename T> std::string to_string(T value) {
|
||||||
#ifdef SK_BUILD_FOR_ANDROID
|
|
||||||
std::stringstream buffer;
|
std::stringstream buffer;
|
||||||
buffer << value;
|
buffer << std::setprecision(std::numeric_limits<T>::digits10) << value;
|
||||||
return buffer.str();
|
return buffer.str();
|
||||||
#else
|
|
||||||
return std::to_string(value);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
|
@ -20,12 +20,13 @@ namespace SkSL {
|
|||||||
*/
|
*/
|
||||||
struct ASTLayout : public ASTNode {
|
struct ASTLayout : public ASTNode {
|
||||||
// For all parameters, a -1 means no value
|
// 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)
|
: fLocation(location)
|
||||||
, fBinding(binding)
|
, fBinding(binding)
|
||||||
, fIndex(index)
|
, fIndex(index)
|
||||||
, fSet(set)
|
, fSet(set)
|
||||||
, fBuiltin(builtin) {}
|
, fBuiltin(builtin)
|
||||||
|
, fOriginUpperLeft(originUpperLeft) {}
|
||||||
|
|
||||||
std::string description() const {
|
std::string description() const {
|
||||||
std::string result;
|
std::string result;
|
||||||
@ -50,6 +51,10 @@ struct ASTLayout : public ASTNode {
|
|||||||
result += separator + "builtin = " + to_string(fBuiltin);
|
result += separator + "builtin = " + to_string(fBuiltin);
|
||||||
separator = ", ";
|
separator = ", ";
|
||||||
}
|
}
|
||||||
|
if (fOriginUpperLeft) {
|
||||||
|
result += separator + "origin_upper_left";
|
||||||
|
separator = ", ";
|
||||||
|
}
|
||||||
if (result.length() > 0) {
|
if (result.length() > 0) {
|
||||||
result = "layout (" + result + ")";
|
result = "layout (" + result + ")";
|
||||||
}
|
}
|
||||||
@ -61,6 +66,7 @@ struct ASTLayout : public ASTNode {
|
|||||||
const int fIndex;
|
const int fIndex;
|
||||||
const int fSet;
|
const int fSet;
|
||||||
const int fBuiltin;
|
const int fBuiltin;
|
||||||
|
const bool fOriginUpperLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -18,14 +18,16 @@ namespace SkSL {
|
|||||||
*/
|
*/
|
||||||
struct ASTModifiers : public ASTNode {
|
struct ASTModifiers : public ASTNode {
|
||||||
enum Flag {
|
enum Flag {
|
||||||
kNo_Flag = 0,
|
kNo_Flag = 0,
|
||||||
kConst_Flag = 1,
|
kConst_Flag = 1,
|
||||||
kIn_Flag = 2,
|
kIn_Flag = 2,
|
||||||
kOut_Flag = 4,
|
kOut_Flag = 4,
|
||||||
kLowp_Flag = 8,
|
kLowp_Flag = 8,
|
||||||
kMediump_Flag = 16,
|
kMediump_Flag = 16,
|
||||||
kHighp_Flag = 32,
|
kHighp_Flag = 32,
|
||||||
kUniform_Flag = 64
|
kUniform_Flag = 64,
|
||||||
|
kFlat_Flag = 128,
|
||||||
|
kNoPerspective_Flag = 256
|
||||||
};
|
};
|
||||||
|
|
||||||
ASTModifiers(ASTLayout layout, int flags)
|
ASTModifiers(ASTLayout layout, int flags)
|
||||||
@ -49,6 +51,12 @@ struct ASTModifiers : public ASTNode {
|
|||||||
if (fFlags & kHighp_Flag) {
|
if (fFlags & kHighp_Flag) {
|
||||||
result += "highp ";
|
result += "highp ";
|
||||||
}
|
}
|
||||||
|
if (fFlags & kFlat_Flag) {
|
||||||
|
result += "flat ";
|
||||||
|
}
|
||||||
|
if (fFlags & kNoPerspective_Flag) {
|
||||||
|
result += "noperspective ";
|
||||||
|
}
|
||||||
|
|
||||||
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
|
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
|
||||||
result += "inout ";
|
result += "inout ";
|
||||||
|
@ -19,7 +19,7 @@ namespace SkSL {
|
|||||||
*/
|
*/
|
||||||
struct ASTNode {
|
struct ASTNode {
|
||||||
virtual ~ASTNode() {}
|
virtual ~ASTNode() {}
|
||||||
|
|
||||||
virtual std::string description() const = 0;
|
virtual std::string description() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ struct BoolLiteral : public Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isConstant() const override {
|
bool isConstant() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool fValue;
|
const bool fValue;
|
||||||
|
@ -17,10 +17,19 @@ namespace SkSL {
|
|||||||
* An expression which extracts a field from a struct, as in 'foo.bar'.
|
* An expression which extracts a field from a struct, as in 'foo.bar'.
|
||||||
*/
|
*/
|
||||||
struct FieldAccess : public Expression {
|
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)
|
: INHERITED(base->fPosition, kFieldAccess_Kind, base->fType.fields()[fieldIndex].fType)
|
||||||
, fBase(std::move(base))
|
, fBase(std::move(base))
|
||||||
, fFieldIndex(fieldIndex) {}
|
, fFieldIndex(fieldIndex)
|
||||||
|
, fOwnerKind(ownerKind) {}
|
||||||
|
|
||||||
virtual std::string description() const override {
|
virtual std::string description() const override {
|
||||||
return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
|
return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
|
||||||
@ -28,6 +37,7 @@ struct FieldAccess : public Expression {
|
|||||||
|
|
||||||
const std::unique_ptr<Expression> fBase;
|
const std::unique_ptr<Expression> fBase;
|
||||||
const int fFieldIndex;
|
const int fFieldIndex;
|
||||||
|
const OwnerKind fOwnerKind;
|
||||||
|
|
||||||
typedef Expression INHERITED;
|
typedef Expression INHERITED;
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ struct FloatLiteral : public Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isConstant() const override {
|
bool isConstant() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const double fValue;
|
const double fValue;
|
||||||
|
@ -24,8 +24,8 @@ struct FunctionReference : public Expression {
|
|||||||
, fFunctions(function) {}
|
, fFunctions(function) {}
|
||||||
|
|
||||||
virtual std::string description() const override {
|
virtual std::string description() const override {
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return "<function>";
|
return "<function>";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const FunctionDeclaration*> fFunctions;
|
const std::vector<const FunctionDeclaration*> fFunctions;
|
||||||
|
@ -27,7 +27,7 @@ struct IntLiteral : public Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isConstant() const override {
|
bool isConstant() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int64_t fValue;
|
const int64_t fValue;
|
||||||
|
@ -21,14 +21,16 @@ struct Layout {
|
|||||||
, fBinding(layout.fBinding)
|
, fBinding(layout.fBinding)
|
||||||
, fIndex(layout.fIndex)
|
, fIndex(layout.fIndex)
|
||||||
, fSet(layout.fSet)
|
, 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)
|
: fLocation(location)
|
||||||
, fBinding(binding)
|
, fBinding(binding)
|
||||||
, fIndex(index)
|
, fIndex(index)
|
||||||
, fSet(set)
|
, fSet(set)
|
||||||
, fBuiltin(builtin) {}
|
, fBuiltin(builtin)
|
||||||
|
, fOriginUpperLeft(originUpperLeft) {}
|
||||||
|
|
||||||
std::string description() const {
|
std::string description() const {
|
||||||
std::string result;
|
std::string result;
|
||||||
@ -53,6 +55,10 @@ struct Layout {
|
|||||||
result += separator + "builtin = " + to_string(fBuiltin);
|
result += separator + "builtin = " + to_string(fBuiltin);
|
||||||
separator = ", ";
|
separator = ", ";
|
||||||
}
|
}
|
||||||
|
if (fOriginUpperLeft) {
|
||||||
|
result += separator + "origin_upper_left";
|
||||||
|
separator = ", ";
|
||||||
|
}
|
||||||
if (result.length() > 0) {
|
if (result.length() > 0) {
|
||||||
result = "layout (" + result + ")";
|
result = "layout (" + result + ")";
|
||||||
}
|
}
|
||||||
@ -71,11 +77,14 @@ struct Layout {
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fLocation;
|
// everything but builtin is in the GLSL spec; builtin comes from SPIR-V and identifies which
|
||||||
const int fBinding;
|
// particular builtin value this object represents.
|
||||||
const int fIndex;
|
int fLocation;
|
||||||
const int fSet;
|
int fBinding;
|
||||||
const int fBuiltin;
|
int fIndex;
|
||||||
|
int fSet;
|
||||||
|
int fBuiltin;
|
||||||
|
bool fOriginUpperLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -18,14 +18,16 @@ namespace SkSL {
|
|||||||
*/
|
*/
|
||||||
struct Modifiers {
|
struct Modifiers {
|
||||||
enum Flag {
|
enum Flag {
|
||||||
kNo_Flag = ASTModifiers::kNo_Flag,
|
kNo_Flag = ASTModifiers::kNo_Flag,
|
||||||
kConst_Flag = ASTModifiers::kConst_Flag,
|
kConst_Flag = ASTModifiers::kConst_Flag,
|
||||||
kIn_Flag = ASTModifiers::kIn_Flag,
|
kIn_Flag = ASTModifiers::kIn_Flag,
|
||||||
kOut_Flag = ASTModifiers::kOut_Flag,
|
kOut_Flag = ASTModifiers::kOut_Flag,
|
||||||
kLowp_Flag = ASTModifiers::kLowp_Flag,
|
kLowp_Flag = ASTModifiers::kLowp_Flag,
|
||||||
kMediump_Flag = ASTModifiers::kMediump_Flag,
|
kMediump_Flag = ASTModifiers::kMediump_Flag,
|
||||||
kHighp_Flag = ASTModifiers::kHighp_Flag,
|
kHighp_Flag = ASTModifiers::kHighp_Flag,
|
||||||
kUniform_Flag = ASTModifiers::kUniform_Flag
|
kUniform_Flag = ASTModifiers::kUniform_Flag,
|
||||||
|
kFlat_Flag = ASTModifiers::kFlat_Flag,
|
||||||
|
kNoPerspective_Flag = ASTModifiers::kNoPerspective_Flag
|
||||||
};
|
};
|
||||||
|
|
||||||
Modifiers(const ASTModifiers& modifiers)
|
Modifiers(const ASTModifiers& modifiers)
|
||||||
@ -53,6 +55,12 @@ struct Modifiers {
|
|||||||
if (fFlags & kHighp_Flag) {
|
if (fFlags & kHighp_Flag) {
|
||||||
result += "highp ";
|
result += "highp ";
|
||||||
}
|
}
|
||||||
|
if (fFlags & kFlat_Flag) {
|
||||||
|
result += "flat ";
|
||||||
|
}
|
||||||
|
if (fFlags & kNoPerspective_Flag) {
|
||||||
|
result += "noperspective ";
|
||||||
|
}
|
||||||
|
|
||||||
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
|
if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) {
|
||||||
result += "inout ";
|
result += "inout ";
|
||||||
@ -73,8 +81,8 @@ struct Modifiers {
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout fLayout;
|
Layout fLayout;
|
||||||
const int fFlags;
|
int fFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -23,8 +23,8 @@ struct TypeReference : public Expression {
|
|||||||
, fValue(type) {}
|
, fValue(type) {}
|
||||||
|
|
||||||
std::string description() const override {
|
std::string description() const override {
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return "<type>";
|
return "<type>";
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type& fValue;
|
const Type& fValue;
|
||||||
|
@ -20,9 +20,9 @@ struct UnresolvedFunction : public Symbol {
|
|||||||
: INHERITED(Position(), kUnresolvedFunction_Kind, funcs[0]->fName)
|
: INHERITED(Position(), kUnresolvedFunction_Kind, funcs[0]->fName)
|
||||||
, fFunctions(std::move(funcs)) {
|
, fFunctions(std::move(funcs)) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (auto func : funcs) {
|
for (auto func : funcs) {
|
||||||
ASSERT(func->fName == fName);
|
ASSERT(func->fName == fName);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,14 +16,15 @@ namespace SkSL {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A variable declaration, which may consist of multiple individual variables. For instance
|
* 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',
|
* 'int x, y = 1, z[4][2];' is a single VarDeclaration. This declaration would have a base type of
|
||||||
* names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
|
* 'int', names ['x', 'y', 'z'], sizes of [[], [], [4, 2]], and values of [null, 1, null].
|
||||||
*/
|
*/
|
||||||
struct VarDeclaration : public ProgramElement {
|
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::vector<std::unique_ptr<Expression>>> sizes,
|
||||||
std::vector<std::unique_ptr<Expression>> values)
|
std::vector<std::unique_ptr<Expression>> values)
|
||||||
: INHERITED(position, kVar_Kind)
|
: INHERITED(position, kVar_Kind)
|
||||||
|
, fBaseType(*baseType)
|
||||||
, fVars(std::move(vars))
|
, fVars(std::move(vars))
|
||||||
, fSizes(std::move(sizes))
|
, fSizes(std::move(sizes))
|
||||||
, fValues(std::move(values)) {}
|
, fValues(std::move(values)) {}
|
||||||
@ -55,6 +56,7 @@ struct VarDeclaration : public ProgramElement {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Type& fBaseType;
|
||||||
const std::vector<const Variable*> fVars;
|
const std::vector<const Variable*> fVars;
|
||||||
const std::vector<std::vector<std::unique_ptr<Expression>>> fSizes;
|
const std::vector<std::vector<std::unique_ptr<Expression>>> fSizes;
|
||||||
const std::vector<std::unique_ptr<Expression>> fValues;
|
const std::vector<std::unique_ptr<Expression>> fValues;
|
||||||
|
@ -40,7 +40,7 @@ struct Variable : public Symbol {
|
|||||||
return fModifiers.description() + fType.fName + " " + fName;
|
return fModifiers.description() + fType.fName + " " + fName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Modifiers fModifiers;
|
mutable Modifiers fModifiers;
|
||||||
const Type& fType;
|
const Type& fType;
|
||||||
const Storage fStorage;
|
const Storage fStorage;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -68,6 +68,10 @@ mediump { return SkSL::Token::MEDIUMP; }
|
|||||||
|
|
||||||
highp { return SkSL::Token::HIGHP; }
|
highp { return SkSL::Token::HIGHP; }
|
||||||
|
|
||||||
|
flat { return SkSL::Token::FLAT; }
|
||||||
|
|
||||||
|
noperspective { return SkSL::Token::NOPERSPECTIVE; }
|
||||||
|
|
||||||
struct { return SkSL::Token::STRUCT; }
|
struct { return SkSL::Token::STRUCT; }
|
||||||
|
|
||||||
layout { return SkSL::Token::LAYOUT; }
|
layout { return SkSL::Token::LAYOUT; }
|
||||||
|
227
tests/SkSLGLSLTest.cpp
Normal file
227
tests/SkSLGLSLTest.cpp
Normal 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");
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user