Line data Source code
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 0 : MemoryLayout(Standard std)
23 0 : : fStd(std) {}
24 :
25 0 : static size_t vector_alignment(size_t componentSize, int columns) {
26 0 : 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 0 : size_t roundUpIfNeeded(size_t raw) const {
35 0 : switch (fStd) {
36 0 : case k140_Standard: return (raw + 15) & ~15;
37 0 : case k430_Standard: return raw;
38 : }
39 0 : ABORT("unreachable");
40 : }
41 :
42 : /**
43 : * Returns a type's required alignment when used as a standalone variable.
44 : */
45 0 : size_t alignment(const Type& type) const {
46 : // See OpenGL Spec 7.6.2.2 Standard Uniform Block Layout
47 0 : switch (type.kind()) {
48 : case Type::kScalar_Kind:
49 0 : return this->size(type);
50 : case Type::kVector_Kind:
51 0 : return vector_alignment(this->size(type.componentType()), type.columns());
52 : case Type::kMatrix_Kind:
53 0 : return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()),
54 0 : type.rows()));
55 : case Type::kArray_Kind:
56 0 : return this->roundUpIfNeeded(this->alignment(type.componentType()));
57 : case Type::kStruct_Kind: {
58 0 : size_t result = 0;
59 0 : for (const auto& f : type.fields()) {
60 0 : size_t alignment = this->alignment(*f.fType);
61 0 : if (alignment > result) {
62 0 : result = alignment;
63 : }
64 : }
65 0 : return this->roundUpIfNeeded(result);
66 : }
67 : default:
68 0 : 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 0 : size_t stride(const Type& type) const {
77 0 : switch (type.kind()) {
78 : case Type::kMatrix_Kind: // fall through
79 : case Type::kArray_Kind:
80 0 : return this->alignment(type);
81 : default:
82 0 : ABORT("type does not have a stride");
83 : }
84 : }
85 :
86 : /**
87 : * Returns the size of a type in bytes.
88 : */
89 0 : size_t size(const Type& type) const {
90 0 : switch (type.kind()) {
91 : case Type::kScalar_Kind:
92 0 : if (type.name() == "bool") {
93 0 : return 1;
94 : }
95 : // FIXME need to take precision into account, once we figure out how we want to
96 : // handle it...
97 0 : return 4;
98 : case Type::kVector_Kind:
99 0 : return type.columns() * this->size(type.componentType());
100 : case Type::kMatrix_Kind: // fall through
101 : case Type::kArray_Kind:
102 0 : return type.columns() * this->stride(type);
103 : case Type::kStruct_Kind: {
104 0 : size_t total = 0;
105 0 : for (const auto& f : type.fields()) {
106 0 : size_t alignment = this->alignment(*f.fType);
107 0 : if (total % alignment != 0) {
108 0 : total += alignment - total % alignment;
109 : }
110 0 : ASSERT(total % alignment == 0);
111 0 : total += this->size(*f.fType);
112 : }
113 0 : size_t alignment = this->alignment(type);
114 0 : ASSERT(!type.fields().size() ||
115 : (0 == alignment % this->alignment(*type.fields()[0].fType)));
116 0 : return (total + alignment - 1) & ~(alignment - 1);
117 : }
118 : default:
119 0 : 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
|