SkSLMemoryLayout.h 4.8 KB

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