OLD | NEW |
(Empty) | |
| 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 t
he 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.c
olumns()); |
| 52 case Type::kMatrix_Kind: |
| 53 return this->roundUpIfNeeded(vector_alignment(this->size(type.co
mponentType()), |
| 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 " + type.name()).c_str()); |
| 69 } |
| 70 } |
| 71 |
| 72 /** |
| 73 * For matrices and arrays, returns the number of bytes from the start of on
e 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 " + type.name()).c_str()); |
| 120 } |
| 121 } |
| 122 |
| 123 const Standard fStd; |
| 124 }; |
| 125 |
| 126 } // namespace |
| 127 |
| 128 #endif |
OLD | NEW |