1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SKIASL_MEMORYLAYOUT 9 #define SKIASL_MEMORYLAYOUT 10 11 #include "ir/SkSLType.h" 12 13 namespace SkSL { 14 15 class MemoryLayout { 16 public: 17 enum Standard { 18 k140_Standard, 19 k430_Standard 20 }; 21 22 MemoryLayout(Standard std) 23 : fStd(std) {} 24 25 static size_t vector_alignment(size_t componentSize, int columns) { 26 return componentSize * (columns + columns % 2); 27 } 28 29 /** 30 * Rounds up to the nearest multiple of 16 if in std140, otherwise returns the parameter 31 * unchanged (std140 requires various things to be rounded up to the nearest multiple of 16, 32 * std430 does not). 33 */ 34 size_t roundUpIfNeeded(size_t raw) const { 35 switch (fStd) { 36 case k140_Standard: return (raw + 15) & ~15; 37 case k430_Standard: return raw; 38 } 39 ABORT("unreachable"); 40 } 41 42 /** 43 * Returns a type's required alignment when used as a standalone variable. 44 */ 45 size_t alignment(const Type& type) const { 46 // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout 47 switch (type.kind()) { 48 case Type::kScalar_Kind: 49 return this->size(type); 50 case Type::kVector_Kind: 51 return vector_alignment(this->size(type.componentType()), type.columns()); 52 case Type::kMatrix_Kind: 53 return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()), 54 type.rows())); 55 case Type::kArray_Kind: 56 return this->roundUpIfNeeded(this->alignment(type.componentType())); 57 case Type::kStruct_Kind: { 58 size_t result = 0; 59 for (const auto& f : type.fields()) { 60 size_t alignment = this->alignment(*f.fType); 61 if (alignment > result) { 62 result = alignment; 63 } 64 } 65 return this->roundUpIfNeeded(result); 66 } 67 default: 68 ABORT("cannot determine size of type %s", type.name().c_str()); 69 } 70 } 71 72 /** 73 * For matrices and arrays, returns the number of bytes from the start of one entry (row, in 74 * the case of matrices) to the start of the next. 75 */ 76 size_t stride(const Type& type) const { 77 switch (type.kind()) { 78 case Type::kMatrix_Kind: // fall through 79 case Type::kArray_Kind: 80 return this->alignment(type); 81 default: 82 ABORT("type does not have a stride"); 83 } 84 } 85 86 /** 87 * Returns the size of a type in bytes. 88 */ 89 size_t size(const Type& type) const { 90 switch (type.kind()) { 91 case Type::kScalar_Kind: 92 if (type.name() == "bool") { 93 return 1; 94 } 95 // FIXME need to take precision into account, once we figure out how we want to 96 // handle it... 97 return 4; 98 case Type::kVector_Kind: 99 return type.columns() * this->size(type.componentType()); 100 case Type::kMatrix_Kind: // fall through 101 case Type::kArray_Kind: 102 return type.columns() * this->stride(type); 103 case Type::kStruct_Kind: { 104 size_t total = 0; 105 for (const auto& f : type.fields()) { 106 size_t alignment = this->alignment(*f.fType); 107 if (total % alignment != 0) { 108 total += alignment - total % alignment; 109 } 110 ASSERT(total % alignment == 0); 111 total += this->size(*f.fType); 112 } 113 size_t alignment = this->alignment(type); 114 ASSERT(!type.fields().size() || 115 (0 == alignment % this->alignment(*type.fields()[0].fType))); 116 return (total + alignment - 1) & ~(alignment - 1); 117 } 118 default: 119 ABORT("cannot determine size of type %s", type.name().c_str()); 120 } 121 } 122 123 const Standard fStd; 124 }; 125 126 } // namespace 127 128 #endif 129