added support for push_constant layout
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2187433003 Review-Url: https://codereview.chromium.org/2187433003
This commit is contained in:
parent
3667b4970d
commit
fa5f65ac61
@ -203,6 +203,7 @@ tests_sources = [
|
||||
"$_tests/SkSharedMutexTest.cpp",
|
||||
"$_tests/SkSLErrorTest.cpp",
|
||||
"$_tests/SkSLGLSLTest.cpp",
|
||||
"$_tests/SkSLMemoryLayoutTest.cpp",
|
||||
"$_tests/SmallAllocatorTest.cpp",
|
||||
"$_tests/SortTest.cpp",
|
||||
"$_tests/SpecialImageTest.cpp",
|
||||
|
128
src/sksl/SkSLMemoryLayout.h
Normal file
128
src/sksl/SkSLMemoryLayout.h
Normal file
@ -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
|
@ -526,8 +526,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;
|
||||
@ -537,11 +536,12 @@ ASTLayout Parser::layout() {
|
||||
bool originUpperLeft = false;
|
||||
bool overrideCoverage = false;
|
||||
bool blendSupportAllEquations = false;
|
||||
bool pushConstant = false;
|
||||
if (this->peek().fKind == Token::LAYOUT) {
|
||||
this->nextToken();
|
||||
if (!this->expect(Token::LPAREN, "'('")) {
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft,
|
||||
overrideCoverage, blendSupportAllEquations);
|
||||
overrideCoverage, blendSupportAllEquations, pushConstant);
|
||||
}
|
||||
for (;;) {
|
||||
Token t = this->nextToken();
|
||||
@ -561,6 +561,8 @@ ASTLayout Parser::layout() {
|
||||
overrideCoverage = true;
|
||||
} else if (t.fText == "blend_support_all_equations") {
|
||||
blendSupportAllEquations = true;
|
||||
} else if (t.fText == "push_constant") {
|
||||
pushConstant = true;
|
||||
} else {
|
||||
this->error(t.fPosition, ("'" + t.fText +
|
||||
"' is not a valid layout qualifier").c_str());
|
||||
@ -575,7 +577,7 @@ ASTLayout Parser::layout() {
|
||||
}
|
||||
}
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft, overrideCoverage,
|
||||
blendSupportAllEquations);
|
||||
blendSupportAllEquations, pushConstant);
|
||||
}
|
||||
|
||||
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
|
||||
|
@ -968,13 +968,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);
|
||||
@ -983,8 +983,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;
|
||||
@ -1000,7 +1000,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();
|
||||
@ -1012,7 +1013,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) {
|
||||
std::string key = type.name() + to_string((int) layout.fStd);
|
||||
auto entry = fTypeMap.find(key);
|
||||
if (entry == fTypeMap.end()) {
|
||||
SpvId result = this->nextId();
|
||||
switch (type.kind()) {
|
||||
@ -1033,35 +1039,38 @@ 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;
|
||||
}
|
||||
case Type::kSampler_Kind: {
|
||||
SpvId 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(),
|
||||
SpvImageFormatUnknown, fConstantBuffer);
|
||||
@ -1075,7 +1084,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;
|
||||
@ -1138,9 +1147,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) {
|
||||
std::string key = type.description() + "*" + to_string(storageClass);
|
||||
std::string key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
|
||||
auto entry = fTypeMap.find(key);
|
||||
if (entry == fTypeMap.end()) {
|
||||
SpvId result = this->nextId();
|
||||
@ -1551,10 +1564,15 @@ SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& o
|
||||
|
||||
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;
|
||||
@ -2358,7 +2376,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);
|
||||
@ -2414,7 +2435,8 @@ 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);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#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)
|
||||
@ -93,17 +95,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, std::ostream& 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, std::ostream& out);
|
||||
|
||||
@ -229,6 +236,7 @@ private:
|
||||
std::ostream& out);
|
||||
|
||||
const Context& fContext;
|
||||
const MemoryLayout fDefaultLayout;
|
||||
|
||||
uint64_t fCapabilities;
|
||||
SpvId fIdCount;
|
||||
|
@ -100,13 +100,8 @@ NORETURN void sksl_abort();
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ASSERT(x) assert(x)
|
||||
#define ASSERT_RESULT(x) ASSERT(x);
|
||||
#else
|
||||
#define ASSERT(x)
|
||||
#define ASSERT_RESULT(x) x
|
||||
#endif
|
||||
#define ASSERT(x) SkASSERT(x)
|
||||
#define ASSERT_RESULT(x) SkAssertResult(x);
|
||||
|
||||
#ifdef SKIA
|
||||
#define ABORT(...) { SkDebugf(__VA_ARGS__); sksl_abort(); }
|
||||
|
@ -19,9 +19,9 @@ namespace SkSL {
|
||||
* layout (location = 0) int x;
|
||||
*/
|
||||
struct ASTLayout : public ASTNode {
|
||||
// For all parameters, a -1 means no value
|
||||
// For int parameters, a -1 means no value
|
||||
ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft,
|
||||
bool overrideCoverage, bool blendSupportAllEquations)
|
||||
bool overrideCoverage, bool blendSupportAllEquations, bool pushConstant)
|
||||
: fLocation(location)
|
||||
, fBinding(binding)
|
||||
, fIndex(index)
|
||||
@ -29,7 +29,8 @@ struct ASTLayout : public ASTNode {
|
||||
, fBuiltin(builtin)
|
||||
, fOriginUpperLeft(originUpperLeft)
|
||||
, fOverrideCoverage(overrideCoverage)
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations) {}
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations)
|
||||
, fPushConstant(pushConstant) {}
|
||||
|
||||
std::string description() const {
|
||||
std::string result;
|
||||
@ -66,6 +67,10 @@ struct ASTLayout : public ASTNode {
|
||||
result += separator + "blend_support_all_equations";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fPushConstant) {
|
||||
result += separator + "push_constant";
|
||||
separator = ", ";
|
||||
}
|
||||
if (result.length() > 0) {
|
||||
result = "layout (" + result + ")";
|
||||
}
|
||||
@ -80,6 +85,7 @@ struct ASTLayout : public ASTNode {
|
||||
const bool fOriginUpperLeft;
|
||||
const bool fOverrideCoverage;
|
||||
const bool fBlendSupportAllEquations;
|
||||
const bool fPushConstant;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -24,10 +24,11 @@ struct Layout {
|
||||
, fBuiltin(layout.fBuiltin)
|
||||
, fOriginUpperLeft(layout.fOriginUpperLeft)
|
||||
, fOverrideCoverage(layout.fOverrideCoverage)
|
||||
, fBlendSupportAllEquations(layout.fBlendSupportAllEquations) {}
|
||||
, fBlendSupportAllEquations(layout.fBlendSupportAllEquations)
|
||||
, fPushConstant(layout.fPushConstant) {}
|
||||
|
||||
Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft,
|
||||
bool overrideCoverage, bool blendSupportAllEquations)
|
||||
bool overrideCoverage, bool blendSupportAllEquations, bool pushconstant)
|
||||
: fLocation(location)
|
||||
, fBinding(binding)
|
||||
, fIndex(index)
|
||||
@ -35,7 +36,19 @@ struct Layout {
|
||||
, fBuiltin(builtin)
|
||||
, fOriginUpperLeft(originUpperLeft)
|
||||
, fOverrideCoverage(overrideCoverage)
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations) {}
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations)
|
||||
, fPushConstant(pushconstant) {}
|
||||
|
||||
Layout()
|
||||
: fLocation(-1)
|
||||
, fBinding(-1)
|
||||
, fIndex(-1)
|
||||
, fSet(-1)
|
||||
, fBuiltin(-1)
|
||||
, fOriginUpperLeft(false)
|
||||
, fOverrideCoverage(false)
|
||||
, fBlendSupportAllEquations(false)
|
||||
, fPushConstant(false) {}
|
||||
|
||||
std::string description() const {
|
||||
std::string result;
|
||||
@ -72,6 +85,10 @@ struct Layout {
|
||||
result += separator + "blend_support_all_equations";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fPushConstant) {
|
||||
result += separator + "push_constant";
|
||||
separator = ", ";
|
||||
}
|
||||
if (result.length() > 0) {
|
||||
result = "layout (" + result + ")";
|
||||
}
|
||||
@ -93,16 +110,16 @@ struct Layout {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// everything but builtin is in the GLSL spec; builtin comes from SPIR-V and identifies which
|
||||
// particular builtin value this object represents.
|
||||
int fLocation;
|
||||
int fBinding;
|
||||
int fIndex;
|
||||
int fSet;
|
||||
int fBuiltin;
|
||||
int fOffset;
|
||||
bool fOriginUpperLeft;
|
||||
bool fOverrideCoverage;
|
||||
bool fBlendSupportAllEquations;
|
||||
bool fPushConstant;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -38,6 +38,10 @@ struct Modifiers {
|
||||
: fLayout(layout)
|
||||
, fFlags(flags) {}
|
||||
|
||||
Modifiers()
|
||||
: fLayout(Layout())
|
||||
, fFlags(0) {}
|
||||
|
||||
std::string description() const {
|
||||
std::string result = fLayout.description();
|
||||
if (fFlags & kUniform_Flag) {
|
||||
|
@ -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.
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "Test.h"
|
||||
|
||||
#if SKIA_SUPPORT_GPU
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
static void test_failure(skiatest::Reporter* r, const char* src, const char* error) {
|
||||
SkSL::Compiler compiler;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "Test.h"
|
||||
|
||||
#if SKIA_SUPPORT_GPU
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
static void test(skiatest::Reporter* r, const char* src, const GrGLSLCaps& caps,
|
||||
const char* expected) {
|
||||
|
176
tests/SkSLMemoryLayoutTest.cpp
Normal file
176
tests/SkSLMemoryLayoutTest.cpp
Normal file
@ -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(), "a", context.fVec3_Type.get());
|
||||
SkSL::Type s1("s1", fields1);
|
||||
REPORTER_ASSERT(r, 16 == layout.size(s1));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s1));
|
||||
|
||||
fields1.emplace_back(SkSL::Modifiers(), "b", context.fFloat_Type.get());
|
||||
SkSL::Type s2("s2", fields1);
|
||||
REPORTER_ASSERT(r, 16 == layout.size(s2));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s2));
|
||||
|
||||
fields1.emplace_back(SkSL::Modifiers(), "c", context.fBool_Type.get());
|
||||
SkSL::Type s3("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(), "a", context.fInt_Type.get());
|
||||
SkSL::Type s4("s4", fields2);
|
||||
REPORTER_ASSERT(r, 16 == layout.size(s4));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s4));
|
||||
|
||||
fields2.emplace_back(SkSL::Modifiers(), "b", context.fVec3_Type.get());
|
||||
SkSL::Type s5("s5", fields2);
|
||||
REPORTER_ASSERT(r, 32 == layout.size(s5));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s5));
|
||||
|
||||
// arrays
|
||||
SkSL::Type array1("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("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(), "a", context.fVec3_Type.get());
|
||||
SkSL::Type s1("s1", fields1);
|
||||
REPORTER_ASSERT(r, 16 == layout.size(s1));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s1));
|
||||
|
||||
fields1.emplace_back(SkSL::Modifiers(), "b", context.fFloat_Type.get());
|
||||
SkSL::Type s2("s2", fields1);
|
||||
REPORTER_ASSERT(r, 16 == layout.size(s2));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s2));
|
||||
|
||||
fields1.emplace_back(SkSL::Modifiers(), "c", context.fBool_Type.get());
|
||||
SkSL::Type s3("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(), "a", context.fInt_Type.get());
|
||||
SkSL::Type s4("s4", fields2);
|
||||
REPORTER_ASSERT(r, 4 == layout.size(s4));
|
||||
REPORTER_ASSERT(r, 4 == layout.alignment(s4));
|
||||
|
||||
fields2.emplace_back(SkSL::Modifiers(), "b", context.fVec3_Type.get());
|
||||
SkSL::Type s5("s5", fields2);
|
||||
REPORTER_ASSERT(r, 32 == layout.size(s5));
|
||||
REPORTER_ASSERT(r, 16 == layout.alignment(s5));
|
||||
|
||||
// arrays
|
||||
SkSL::Type array1("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("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
|
Loading…
Reference in New Issue
Block a user