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 |