|  | /* | 
|  | * 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 |