aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ethannicholas <ethannicholas@google.com>2016-11-22 08:39:36 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-11-22 08:39:36 -0800
commit8ac838d978578c44b75a801489c985e5284dd66f (patch)
treeb53cdcf94cdd49e3d7867099d0d2018a41fc1a05
parent64773e6c9f61fb319f597a8d7dd7ee377d51a43a (diff)
added support for push_constant layout
-rw-r--r--gn/tests.gni1
-rw-r--r--src/sksl/SkSLMemoryLayout.h128
-rw-r--r--src/sksl/SkSLParser.cpp11
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.cpp57
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.h10
-rw-r--r--src/sksl/ast/SkSLASTLayout.h10
-rw-r--r--src/sksl/ir/SkSLLayout.h16
-rw-r--r--src/sksl/ir/SkSLType.h81
-rw-r--r--tests/SkSLMemoryLayoutTest.cpp176
9 files changed, 380 insertions, 110 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 2cf9d330fc..98980ec0f6 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -204,6 +204,7 @@ tests_sources = [
"$_tests/SkSharedMutexTest.cpp",
"$_tests/SkSLErrorTest.cpp",
"$_tests/SkSLGLSLTest.cpp",
+ "$_tests/SkSLMemoryLayoutTest.cpp",
"$_tests/SmallAllocatorTest.cpp",
"$_tests/SortTest.cpp",
"$_tests/SpecialImageTest.cpp",
diff --git a/src/sksl/SkSLMemoryLayout.h b/src/sksl/SkSLMemoryLayout.h
new file mode 100644
index 0000000000..95a292f9d9
--- /dev/null
+++ b/src/sksl/SkSLMemoryLayout.h
@@ -0,0 +1,128 @@
+/*
+ * 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 SKIASL_MEMORYLAYOUT
+#define SKIASL_MEMORYLAYOUT
+
+#include "ir/SkSLType.h"
+
+namespace SkSL {
+
+class MemoryLayout {
+public:
+ enum Standard {
+ k140_Standard,
+ k430_Standard
+ };
+
+ MemoryLayout(Standard std)
+ : fStd(std) {}
+
+ static size_t vector_alignment(size_t componentSize, int columns) {
+ return componentSize * (columns + columns % 2);
+ }
+
+ /**
+ * Rounds up to the nearest multiple of 16 if in std140, otherwise returns the parameter
+ * unchanged (std140 requires various things to be rounded up to the nearest multiple of 16,
+ * std430 does not).
+ */
+ size_t roundUpIfNeeded(size_t raw) const {
+ switch (fStd) {
+ case k140_Standard: return (raw + 15) & ~15;
+ case k430_Standard: return raw;
+ }
+ ABORT("unreachable");
+ }
+
+ /**
+ * Returns a type's required alignment when used as a standalone variable.
+ */
+ size_t alignment(const Type& type) const {
+ // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout
+ switch (type.kind()) {
+ case Type::kScalar_Kind:
+ return this->size(type);
+ case Type::kVector_Kind:
+ return vector_alignment(this->size(type.componentType()), type.columns());
+ case Type::kMatrix_Kind:
+ return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()),
+ type.rows()));
+ case Type::kArray_Kind:
+ return this->roundUpIfNeeded(this->alignment(type.componentType()));
+ case Type::kStruct_Kind: {
+ size_t result = 0;
+ for (const auto& f : type.fields()) {
+ size_t alignment = this->alignment(*f.fType);
+ if (alignment > result) {
+ result = alignment;
+ }
+ }
+ return this->roundUpIfNeeded(result);
+ }
+ default:
+ ABORT(("cannot determine size of type " + type.name()).c_str());
+ }
+ }
+
+ /**
+ * For matrices and arrays, returns the number of bytes from the start of one entry (row, in
+ * the case of matrices) to the start of the next.
+ */
+ size_t stride(const Type& type) const {
+ switch (type.kind()) {
+ case Type::kMatrix_Kind: // fall through
+ case Type::kArray_Kind:
+ return this->alignment(type);
+ default:
+ ABORT("type does not have a stride");
+ }
+ }
+
+ /**
+ * Returns the size of a type in bytes.
+ */
+ size_t size(const Type& type) const {
+ switch (type.kind()) {
+ case Type::kScalar_Kind:
+ if (type.name() == "bool") {
+ return 1;
+ }
+ // FIXME need to take precision into account, once we figure out how we want to
+ // handle it...
+ return 4;
+ case Type::kVector_Kind:
+ return type.columns() * this->size(type.componentType());
+ case Type::kMatrix_Kind: // fall through
+ case Type::kArray_Kind:
+ return type.columns() * this->stride(type);
+ case Type::kStruct_Kind: {
+ size_t total = 0;
+ for (const auto& f : type.fields()) {
+ size_t alignment = this->alignment(*f.fType);
+ if (total % alignment != 0) {
+ total += alignment - total % alignment;
+ }
+ ASSERT(total % alignment == 0);
+ total += this->size(*f.fType);
+ }
+ size_t alignment = this->alignment(type);
+ ASSERT(!type.fields().size() ||
+ (0 == alignment % this->alignment(*type.fields()[0].fType)));
+ return (total + alignment - 1) & ~(alignment - 1);
+ }
+ default:
+ ABORT(("cannot determine size of type " + type.name()).c_str());
+ }
+ }
+
+ const Standard fStd;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index 58ec750168..80ef870a48 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -535,8 +535,7 @@ int Parser::layoutInt() {
return -1;
}
-/* LAYOUT LPAREN IDENTIFIER EQ INT_LITERAL (COMMA IDENTIFIER EQ INT_LITERAL)*
- RPAREN */
+/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
ASTLayout Parser::layout() {
int location = -1;
int binding = -1;
@@ -548,11 +547,13 @@ ASTLayout Parser::layout() {
bool overrideCoverage = false;
bool blendSupportAllEquations = false;
ASTLayout::Format format = ASTLayout::Format::kUnspecified;
+ bool pushConstant = false;
if (this->peek().fKind == Token::LAYOUT) {
this->nextToken();
if (!this->expect(Token::LPAREN, "'('")) {
return ASTLayout(location, binding, index, set, builtin, inputAttachmentIndex,
- originUpperLeft, overrideCoverage, blendSupportAllEquations, format);
+ originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
+ pushConstant);
}
for (;;) {
Token t = this->nextToken();
@@ -576,6 +577,8 @@ ASTLayout Parser::layout() {
blendSupportAllEquations = true;
} else if (ASTLayout::ReadFormat(t.fText, &format)) {
// AST::ReadFormat stored the result in 'format'.
+ } else if (t.fText == "push_constant") {
+ pushConstant = true;
} else {
this->error(t.fPosition, ("'" + t.fText +
"' is not a valid layout qualifier").c_str());
@@ -590,7 +593,7 @@ ASTLayout Parser::layout() {
}
}
return ASTLayout(location, binding, index, set, builtin, inputAttachmentIndex, originUpperLeft,
- overrideCoverage, blendSupportAllEquations, format);
+ overrideCoverage, blendSupportAllEquations, format, pushConstant);
}
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 300d3c5d66..ecde11509d 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -975,13 +975,13 @@ SpvId SPIRVCodeGenerator::nextId() {
return fIdCount++;
}
-void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
+void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId) {
this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
// go ahead and write all of the field types, so we don't inadvertently write them while we're
// in the middle of writing the struct instruction
std::vector<SpvId> types;
for (const auto& f : type.fields()) {
- types.push_back(this->getType(*f.fType));
+ types.push_back(this->getType(*f.fType, layout));
}
this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
this->writeWord(resultId, fConstantBuffer);
@@ -990,8 +990,8 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
}
size_t offset = 0;
for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
- size_t size = type.fields()[i].fType->size();
- size_t alignment = type.fields()[i].fType->alignment();
+ size_t size = layout.size(*type.fields()[i].fType);
+ size_t alignment = layout.alignment(*type.fields()[i].fType);
size_t mod = offset % alignment;
if (mod != 0) {
offset += alignment - mod;
@@ -1007,7 +1007,8 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
fDecorationBuffer);
this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
- (SpvId) type.fields()[i].fType->stride(), fDecorationBuffer);
+ (SpvId) layout.stride(*type.fields()[i].fType),
+ fDecorationBuffer);
}
offset += size;
Type::Kind kind = type.fields()[i].fType->kind();
@@ -1018,7 +1019,12 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
}
SpvId SPIRVCodeGenerator::getType(const Type& type) {
- auto entry = fTypeMap.find(type.name());
+ return this->getType(type, fDefaultLayout);
+}
+
+SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
+ SkString key = type.name() + to_string((int) layout.fStd);
+ auto entry = fTypeMap.find(key);
if (entry == fTypeMap.end()) {
SpvId result = this->nextId();
switch (type.kind()) {
@@ -1039,29 +1045,31 @@ SpvId SPIRVCodeGenerator::getType(const Type& type) {
break;
case Type::kVector_Kind:
this->writeInstruction(SpvOpTypeVector, result,
- this->getType(type.componentType()),
+ this->getType(type.componentType(), layout),
type.columns(), fConstantBuffer);
break;
case Type::kMatrix_Kind:
this->writeInstruction(SpvOpTypeMatrix, result,
- this->getType(index_type(fContext, type)),
+ this->getType(index_type(fContext, type), layout),
type.columns(), fConstantBuffer);
break;
case Type::kStruct_Kind:
- this->writeStruct(type, result);
+ this->writeStruct(type, layout, result);
break;
case Type::kArray_Kind: {
if (type.columns() > 0) {
IntLiteral count(fContext, Position(), type.columns());
this->writeInstruction(SpvOpTypeArray, result,
- this->getType(type.componentType()),
+ this->getType(type.componentType(), layout),
this->writeIntLiteral(count), fConstantBuffer);
this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
- (int32_t) type.stride(), fDecorationBuffer);
+ (int32_t) layout.stride(type),
+ fDecorationBuffer);
} else {
ABORT("runtime-sized arrays are not yet supported");
this->writeInstruction(SpvOpTypeRuntimeArray, result,
- this->getType(type.componentType()), fConstantBuffer);
+ this->getType(type.componentType(), layout),
+ fConstantBuffer);
}
break;
}
@@ -1070,7 +1078,8 @@ SpvId SPIRVCodeGenerator::getType(const Type& type) {
if (SpvDimSubpassData != type.dimensions()) {
image = this->nextId();
}
- this->writeInstruction(SpvOpTypeImage, image, this->getType(*fContext.fFloat_Type),
+ this->writeInstruction(SpvOpTypeImage, image,
+ this->getType(*fContext.fFloat_Type, layout),
type.dimensions(), type.isDepth(), type.isArrayed(),
type.isMultisampled(), type.isSampled() ? 1 : 2,
SpvImageFormatUnknown, fConstantBuffer);
@@ -1086,7 +1095,7 @@ SpvId SPIRVCodeGenerator::getType(const Type& type) {
ABORT("invalid type: %s", type.description().c_str());
}
}
- fTypeMap[type.name()] = result;
+ fTypeMap[key] = result;
return result;
}
return entry->second;
@@ -1149,9 +1158,13 @@ SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
return entry->second;
}
-SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
+SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
+ return this->getPointerType(type, fDefaultLayout, storageClass);
+}
+
+SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
SpvStorageClass_ storageClass) {
- SkString key = type.description() + "*" + to_string(storageClass);
+ SkString key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
auto entry = fTypeMap.find(key);
if (entry == fTypeMap.end()) {
SpvId result = this->nextId();
@@ -1590,10 +1603,15 @@ SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, SkWStream& out)
SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
if (modifiers.fFlags & Modifiers::kIn_Flag) {
+ ASSERT(!modifiers.fLayout.fPushConstant);
return SpvStorageClassInput;
} else if (modifiers.fFlags & Modifiers::kOut_Flag) {
+ ASSERT(!modifiers.fLayout.fPushConstant);
return SpvStorageClassOutput;
} else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
+ if (modifiers.fLayout.fPushConstant) {
+ return SpvStorageClassPushConstant;
+ }
return SpvStorageClassUniform;
} else {
return SpvStorageClassFunction;
@@ -2404,7 +2422,10 @@ void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int mem
}
SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
- SpvId type = this->getType(intf.fVariable.fType);
+ MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
+ MemoryLayout(MemoryLayout::k430_Standard) :
+ fDefaultLayout;
+ SpvId type = this->getType(intf.fVariable.fType, layout);
SpvId result = this->nextId();
this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
@@ -2460,7 +2481,7 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio
this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
fDecorationBuffer);
this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
- (SpvId) var->fType.stride(), fDecorationBuffer);
+ (SpvId) fDefaultLayout.stride(var->fType), fDecorationBuffer);
}
if (varDecl.fValue) {
ASSERT(!fCurrentBlock);
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h
index b79194500a..c885ffc3ff 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/SkSLSPIRVCodeGenerator.h
@@ -14,6 +14,7 @@
#include "SkStream.h"
#include "SkSLCodeGenerator.h"
+#include "SkSLMemoryLayout.h"
#include "ir/SkSLBinaryExpression.h"
#include "ir/SkSLBoolLiteral.h"
#include "ir/SkSLConstructor.h"
@@ -63,6 +64,7 @@ public:
SPIRVCodeGenerator(const Context* context)
: fContext(*context)
+ , fDefaultLayout(MemoryLayout::k140_Standard)
, fCapabilities(1 << SpvCapabilityShader)
, fIdCount(1)
, fBoolTrue(0)
@@ -94,17 +96,22 @@ private:
SpvId getType(const Type& type);
+ SpvId getType(const Type& type, const MemoryLayout& layout);
+
SpvId getFunctionType(const FunctionDeclaration& function);
SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
+ SpvId getPointerType(const Type& type, const MemoryLayout& layout,
+ SpvStorageClass_ storageClass);
+
std::vector<SpvId> getAccessChain(const Expression& expr, SkWStream& out);
void writeLayout(const Layout& layout, SpvId target);
void writeLayout(const Layout& layout, SpvId target, int member);
- void writeStruct(const Type& type, SpvId resultId);
+ void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId);
void writeProgramElement(const ProgramElement& pe, SkWStream& out);
@@ -230,6 +237,7 @@ private:
SkWStream& out);
const Context& fContext;
+ const MemoryLayout fDefaultLayout;
uint64_t fCapabilities;
SpvId fIdCount;
diff --git a/src/sksl/ast/SkSLASTLayout.h b/src/sksl/ast/SkSLASTLayout.h
index a77e8388ed..4c36af46a1 100644
--- a/src/sksl/ast/SkSLASTLayout.h
+++ b/src/sksl/ast/SkSLASTLayout.h
@@ -80,7 +80,7 @@ struct ASTLayout : public ASTNode {
// For int parameters, a -1 means no value
ASTLayout(int location, int binding, int index, int set, int builtin, int inputAttachmentIndex,
bool originUpperLeft, bool overrideCoverage, bool blendSupportAllEquations,
- Format format)
+ Format format, bool pushConstant)
: fLocation(location)
, fBinding(binding)
, fIndex(index)
@@ -90,7 +90,8 @@ struct ASTLayout : public ASTNode {
, fOriginUpperLeft(originUpperLeft)
, fOverrideCoverage(overrideCoverage)
, fBlendSupportAllEquations(blendSupportAllEquations)
- , fFormat(format) {}
+ , fFormat(format)
+ , fPushConstant(pushConstant) {}
SkString description() const {
SkString result;
@@ -135,6 +136,10 @@ struct ASTLayout : public ASTNode {
result += separator + FormatToStr(fFormat);
separator = ", ";
}
+ if (fPushConstant) {
+ result += separator + "push_constant";
+ separator = ", ";
+ }
if (result.size() > 0) {
result = "layout (" + result + ")";
}
@@ -151,6 +156,7 @@ struct ASTLayout : public ASTNode {
const bool fOverrideCoverage;
const bool fBlendSupportAllEquations;
const Format fFormat;
+ const bool fPushConstant;
};
} // namespace
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index c5753e010c..f433614da9 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -26,11 +26,12 @@ struct Layout {
, fOriginUpperLeft(layout.fOriginUpperLeft)
, fOverrideCoverage(layout.fOverrideCoverage)
, fBlendSupportAllEquations(layout.fBlendSupportAllEquations)
- , fFormat(layout.fFormat) {}
+ , fFormat(layout.fFormat)
+ , fPushConstant(layout.fPushConstant) {}
Layout(int location, int binding, int index, int set, int builtin, int inputAttachmentIndex,
bool originUpperLeft, bool overrideCoverage, bool blendSupportAllEquations,
- ASTLayout::Format format)
+ ASTLayout::Format format, bool pushconstant)
: fLocation(location)
, fBinding(binding)
, fIndex(index)
@@ -40,7 +41,8 @@ struct Layout {
, fOriginUpperLeft(originUpperLeft)
, fOverrideCoverage(overrideCoverage)
, fBlendSupportAllEquations(blendSupportAllEquations)
- , fFormat(format) {}
+ , fFormat(format)
+ , fPushConstant(pushconstant) {}
Layout()
: fLocation(-1)
@@ -52,7 +54,8 @@ struct Layout {
, fOriginUpperLeft(false)
, fOverrideCoverage(false)
, fBlendSupportAllEquations(false)
- , fFormat(ASTLayout::Format::kUnspecified) {}
+ , fFormat(ASTLayout::Format::kUnspecified)
+ , fPushConstant(false) {}
SkString description() const {
SkString result;
@@ -97,6 +100,10 @@ struct Layout {
result += separator + ASTLayout::FormatToStr(fFormat);
separator = ", ";
}
+ if (fPushConstant) {
+ result += separator + "push_constant";
+ separator = ", ";
+ }
if (result.size() > 0) {
result = "layout (" + result + ")";
}
@@ -134,6 +141,7 @@ struct Layout {
bool fOverrideCoverage;
bool fBlendSupportAllEquations;
ASTLayout::Format fFormat;
+ bool fPushConstant;
};
} // namespace
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index 81ec13ab44..a4632061ae 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -238,87 +238,6 @@ public:
return fIsSampled;
}
- static size_t vector_alignment(size_t componentSize, int columns) {
- return componentSize * (columns + columns % 2);
- }
-
- /**
- * Returns the type's required alignment (when putting this type into a struct, the offset must
- * be a multiple of the alignment).
- */
- size_t alignment() const {
- // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout
- switch (fTypeKind) {
- case kScalar_Kind:
- return this->size();
- case kVector_Kind:
- return vector_alignment(fComponentType->size(), fColumns);
- case kMatrix_Kind:
- return (vector_alignment(fComponentType->size(), fRows) + 15) & ~15;
- case kArray_Kind:
- // round up to next multiple of 16
- return (fComponentType->alignment() + 15) & ~15;
- case kStruct_Kind: {
- size_t result = 16;
- for (size_t i = 0; i < fFields.size(); i++) {
- size_t alignment = fFields[i].fType->alignment();
- if (alignment > result) {
- result = alignment;
- }
- }
- }
- default:
- ABORT(("cannot determine size of type " + fName).c_str());
- }
- }
-
- /**
- * For matrices and arrays, returns the number of bytes from the start of one entry (row, in
- * the case of matrices) to the start of the next.
- */
- size_t stride() const {
- switch (fTypeKind) {
- case kMatrix_Kind: // fall through
- case kArray_Kind:
- return this->alignment();
- default:
- ABORT("type does not have a stride");
- }
- }
-
- /**
- * Returns the size of this type in bytes.
- */
- size_t size() const {
- switch (fTypeKind) {
- case kScalar_Kind:
- // FIXME need to take precision into account, once we figure out how we want to
- // handle it...
- return 4;
- case kVector_Kind:
- return fColumns * fComponentType->size();
- case kMatrix_Kind:
- return vector_alignment(fComponentType->size(), fRows) * fColumns;
- case kArray_Kind:
- return fColumns * this->stride();
- case kStruct_Kind: {
- size_t total = 0;
- for (size_t i = 0; i < fFields.size(); i++) {
- size_t alignment = fFields[i].fType->alignment();
- if (total % alignment != 0) {
- total += alignment - total % alignment;
- }
- ASSERT(false);
- ASSERT(total % alignment == 0);
- total += fFields[i].fType->size();
- }
- return total;
- }
- default:
- ABORT(("cannot determine size of type " + fName).c_str());
- }
- }
-
/**
* Returns the corresponding vector or matrix type with the specified number of columns and
* rows.
diff --git a/tests/SkSLMemoryLayoutTest.cpp b/tests/SkSLMemoryLayoutTest.cpp
new file mode 100644
index 0000000000..336d8aa477
--- /dev/null
+++ b/tests/SkSLMemoryLayoutTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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 "SkSLContext.h"
+#include "SkSLMemoryLayout.h"
+
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+DEF_TEST(SkSLMemoryLayout140Test, r) {
+ SkSL::Context context;
+ SkSL::MemoryLayout layout(SkSL::MemoryLayout::k140_Standard);
+
+ // basic types
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fFloat_Type));
+ REPORTER_ASSERT(r, 8 == layout.size(*context.fVec2_Type));
+ REPORTER_ASSERT(r, 12 == layout.size(*context.fVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.size(*context.fVec4_Type));
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fInt_Type));
+ REPORTER_ASSERT(r, 8 == layout.size(*context.fIVec2_Type));
+ REPORTER_ASSERT(r, 12 == layout.size(*context.fIVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.size(*context.fIVec4_Type));
+ REPORTER_ASSERT(r, 1 == layout.size(*context.fBool_Type));
+ REPORTER_ASSERT(r, 2 == layout.size(*context.fBVec2_Type));
+ REPORTER_ASSERT(r, 3 == layout.size(*context.fBVec3_Type));
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fBVec4_Type));
+ REPORTER_ASSERT(r, 32 == layout.size(*context.fMat2x2_Type));
+ REPORTER_ASSERT(r, 32 == layout.size(*context.fMat2x4_Type));
+ REPORTER_ASSERT(r, 48 == layout.size(*context.fMat3x3_Type));
+ REPORTER_ASSERT(r, 64 == layout.size(*context.fMat4x2_Type));
+ REPORTER_ASSERT(r, 64 == layout.size(*context.fMat4x4_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fFloat_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fVec2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fVec4_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fInt_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fIVec2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fIVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fIVec4_Type));
+ REPORTER_ASSERT(r, 1 == layout.alignment(*context.fBool_Type));
+ REPORTER_ASSERT(r, 2 == layout.alignment(*context.fBVec2_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fBVec3_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fBVec4_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat2x2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat2x4_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat3x3_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat4x2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat4x4_Type));
+
+ // struct 1
+ std::vector<SkSL::Type::Field> fields1;
+ fields1.emplace_back(SkSL::Modifiers(), SkString("a"), context.fVec3_Type.get());
+ SkSL::Type s1(SkString("s1"), fields1);
+ REPORTER_ASSERT(r, 16 == layout.size(s1));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s1));
+
+ fields1.emplace_back(SkSL::Modifiers(), SkString("b"), context.fFloat_Type.get());
+ SkSL::Type s2(SkString("s2"), fields1);
+ REPORTER_ASSERT(r, 16 == layout.size(s2));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s2));
+
+ fields1.emplace_back(SkSL::Modifiers(), SkString("c"), context.fBool_Type.get());
+ SkSL::Type s3(SkString("s3"), fields1);
+ REPORTER_ASSERT(r, 32 == layout.size(s3));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s3));
+
+ // struct 2
+ std::vector<SkSL::Type::Field> fields2;
+ fields2.emplace_back(SkSL::Modifiers(), SkString("a"), context.fInt_Type.get());
+ SkSL::Type s4(SkString("s4"), fields2);
+ REPORTER_ASSERT(r, 16 == layout.size(s4));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s4));
+
+ fields2.emplace_back(SkSL::Modifiers(), SkString("b"), context.fVec3_Type.get());
+ SkSL::Type s5(SkString("s5"), fields2);
+ REPORTER_ASSERT(r, 32 == layout.size(s5));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s5));
+
+ // arrays
+ SkSL::Type array1(SkString("float[4]"), SkSL::Type::kArray_Kind, *context.fFloat_Type, 4);
+ REPORTER_ASSERT(r, 64 == layout.size(array1));
+ REPORTER_ASSERT(r, 16 == layout.alignment(array1));
+ REPORTER_ASSERT(r, 16 == layout.stride(array1));
+
+ SkSL::Type array2(SkString("vec4[4]"), SkSL::Type::kArray_Kind, *context.fVec4_Type, 4);
+ REPORTER_ASSERT(r, 64 == layout.size(array2));
+ REPORTER_ASSERT(r, 16 == layout.alignment(array2));
+ REPORTER_ASSERT(r, 16 == layout.stride(array2));
+}
+
+DEF_TEST(SkSLMemoryLayout430Test, r) {
+ SkSL::Context context;
+ SkSL::MemoryLayout layout(SkSL::MemoryLayout::k430_Standard);
+
+ // basic types
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fFloat_Type));
+ REPORTER_ASSERT(r, 8 == layout.size(*context.fVec2_Type));
+ REPORTER_ASSERT(r, 12 == layout.size(*context.fVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.size(*context.fVec4_Type));
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fInt_Type));
+ REPORTER_ASSERT(r, 8 == layout.size(*context.fIVec2_Type));
+ REPORTER_ASSERT(r, 12 == layout.size(*context.fIVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.size(*context.fIVec4_Type));
+ REPORTER_ASSERT(r, 1 == layout.size(*context.fBool_Type));
+ REPORTER_ASSERT(r, 2 == layout.size(*context.fBVec2_Type));
+ REPORTER_ASSERT(r, 3 == layout.size(*context.fBVec3_Type));
+ REPORTER_ASSERT(r, 4 == layout.size(*context.fBVec4_Type));
+ REPORTER_ASSERT(r, 16 == layout.size(*context.fMat2x2_Type));
+ REPORTER_ASSERT(r, 32 == layout.size(*context.fMat2x4_Type));
+ REPORTER_ASSERT(r, 48 == layout.size(*context.fMat3x3_Type));
+ REPORTER_ASSERT(r, 32 == layout.size(*context.fMat4x2_Type));
+ REPORTER_ASSERT(r, 64 == layout.size(*context.fMat4x4_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fFloat_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fVec2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fVec4_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fInt_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fIVec2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fIVec3_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fIVec4_Type));
+ REPORTER_ASSERT(r, 1 == layout.alignment(*context.fBool_Type));
+ REPORTER_ASSERT(r, 2 == layout.alignment(*context.fBVec2_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fBVec3_Type));
+ REPORTER_ASSERT(r, 4 == layout.alignment(*context.fBVec4_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fMat2x2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat2x4_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat3x3_Type));
+ REPORTER_ASSERT(r, 8 == layout.alignment(*context.fMat4x2_Type));
+ REPORTER_ASSERT(r, 16 == layout.alignment(*context.fMat4x4_Type));
+
+ // struct 1
+ std::vector<SkSL::Type::Field> fields1;
+ fields1.emplace_back(SkSL::Modifiers(), SkString("a"), context.fVec3_Type.get());
+ SkSL::Type s1(SkString("s1"), fields1);
+ REPORTER_ASSERT(r, 16 == layout.size(s1));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s1));
+
+ fields1.emplace_back(SkSL::Modifiers(), SkString("b"), context.fFloat_Type.get());
+ SkSL::Type s2(SkString("s2"), fields1);
+ REPORTER_ASSERT(r, 16 == layout.size(s2));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s2));
+
+ fields1.emplace_back(SkSL::Modifiers(), SkString("c"), context.fBool_Type.get());
+ SkSL::Type s3(SkString("s3"), fields1);
+ REPORTER_ASSERT(r, 32 == layout.size(s3));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s3));
+
+ // struct 2
+ std::vector<SkSL::Type::Field> fields2;
+ fields2.emplace_back(SkSL::Modifiers(), SkString("a"), context.fInt_Type.get());
+ SkSL::Type s4(SkString("s4"), fields2);
+ REPORTER_ASSERT(r, 4 == layout.size(s4));
+ REPORTER_ASSERT(r, 4 == layout.alignment(s4));
+
+ fields2.emplace_back(SkSL::Modifiers(), SkString("b"), context.fVec3_Type.get());
+ SkSL::Type s5(SkString("s5"), fields2);
+ REPORTER_ASSERT(r, 32 == layout.size(s5));
+ REPORTER_ASSERT(r, 16 == layout.alignment(s5));
+
+ // arrays
+ SkSL::Type array1(SkString("float[4]"), SkSL::Type::kArray_Kind, *context.fFloat_Type, 4);
+ REPORTER_ASSERT(r, 16 == layout.size(array1));
+ REPORTER_ASSERT(r, 4 == layout.alignment(array1));
+ REPORTER_ASSERT(r, 4 == layout.stride(array1));
+
+ SkSL::Type array2(SkString("vec4[4]"), SkSL::Type::kArray_Kind, *context.fVec4_Type, 4);
+ REPORTER_ASSERT(r, 64 == layout.size(array2));
+ REPORTER_ASSERT(r, 16 == layout.alignment(array2));
+ REPORTER_ASSERT(r, 16 == layout.stride(array2));
+}
+#endif