• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/Limits.h"
16 
17 #include "common/Assert.h"
18 
19 #include <array>
20 
21 // clang-format off
22 // TODO(crbug.com/dawn/685):
23 // For now, only expose these tiers until metrics can determine better ones.
24 #define LIMITS_WORKGROUP_STORAGE_SIZE(X)                                  \
25     X(Higher, maxComputeWorkgroupStorageSize, 16352, 32768, 49152, 65536)
26 
27 #define LIMITS_STORAGE_BUFFER_BINDING_SIZE(X)                                             \
28     X(Higher, maxStorageBufferBindingSize, 134217728, 1073741824, 2147483647, 4294967295)
29 
30 // TODO(crbug.com/dawn/685):
31 // These limits don't have tiers yet. Define two tiers with the same values since the macros
32 // in this file expect more than one tier.
33 #define LIMITS_OTHER(X)                                                \
34     X(Higher,                     maxTextureDimension1D,  8192,  8192) \
35     X(Higher,                     maxTextureDimension2D,  8192,  8192) \
36     X(Higher,                     maxTextureDimension3D,  2048,  2048) \
37     X(Higher,                     maxTextureArrayLayers,   256,   256) \
38     X(Higher,                             maxBindGroups,     4,     4) \
39     X(Higher, maxDynamicUniformBuffersPerPipelineLayout,     8,     8) \
40     X(Higher, maxDynamicStorageBuffersPerPipelineLayout,     4,     4) \
41     X(Higher,          maxSampledTexturesPerShaderStage,    16,    16) \
42     X(Higher,                 maxSamplersPerShaderStage,    16,    16) \
43     X(Higher,           maxStorageBuffersPerShaderStage,     8,     8) \
44     X(Higher,          maxStorageTexturesPerShaderStage,     4,     4) \
45     X(Higher,           maxUniformBuffersPerShaderStage,    12,    12) \
46     X(Higher,               maxUniformBufferBindingSize, 16384, 16384) \
47     X( Lower,           minUniformBufferOffsetAlignment,   256,   256) \
48     X( Lower,           minStorageBufferOffsetAlignment,   256,   256) \
49     X(Higher,                          maxVertexBuffers,     8,     8) \
50     X(Higher,                       maxVertexAttributes,    16,    16) \
51     X(Higher,                maxVertexBufferArrayStride,  2048,  2048) \
52     X(Higher,             maxInterStageShaderComponents,    60,    60) \
53     X(Higher,         maxComputeInvocationsPerWorkgroup,   256,   256) \
54     X(Higher,                  maxComputeWorkgroupSizeX,   256,   256) \
55     X(Higher,                  maxComputeWorkgroupSizeY,   256,   256) \
56     X(Higher,                  maxComputeWorkgroupSizeZ,    64,    64) \
57     X(Higher,          maxComputeWorkgroupsPerDimension, 65535, 65535)
58 // clang-format on
59 
60 #define LIMITS_EACH_GROUP(X)              \
61     X(LIMITS_WORKGROUP_STORAGE_SIZE)      \
62     X(LIMITS_STORAGE_BUFFER_BINDING_SIZE) \
63     X(LIMITS_OTHER)
64 
65 #define LIMITS(X)                         \
66     LIMITS_WORKGROUP_STORAGE_SIZE(X)      \
67     LIMITS_STORAGE_BUFFER_BINDING_SIZE(X) \
68     LIMITS_OTHER(X)
69 
70 namespace dawn_native {
71     namespace {
72         template <uint32_t A, uint32_t B>
StaticAssertSame()73         constexpr void StaticAssertSame() {
74             static_assert(A == B, "Mismatching tier count in limit group.");
75         }
76 
77         template <uint32_t I, uint32_t... Is>
ReduceSameValue(std::integer_sequence<uint32_t,I,Is...>)78         constexpr uint32_t ReduceSameValue(std::integer_sequence<uint32_t, I, Is...>) {
79             int unused[] = {0, (StaticAssertSame<I, Is>(), 0)...};
80             DAWN_UNUSED(unused);
81             return I;
82         }
83 
84         enum class LimitBetterDirection {
85             Lower,
86             Higher,
87         };
88 
89         template <LimitBetterDirection Better>
90         struct CheckLimit;
91 
92         template <>
93         struct CheckLimit<LimitBetterDirection::Lower> {
94             template <typename T>
IsBetterdawn_native::__anondafefa560111::CheckLimit95             static bool IsBetter(T lhs, T rhs) {
96                 return lhs < rhs;
97             }
98 
99             template <typename T>
Validatedawn_native::__anondafefa560111::CheckLimit100             static MaybeError Validate(T supported, T required) {
101                 DAWN_INVALID_IF(IsBetter(required, supported),
102                                 "Required limit (%u) is lower than the supported limit (%u).",
103                                 required, supported);
104                 return {};
105             }
106         };
107 
108         template <>
109         struct CheckLimit<LimitBetterDirection::Higher> {
110             template <typename T>
IsBetterdawn_native::__anondafefa560111::CheckLimit111             static bool IsBetter(T lhs, T rhs) {
112                 return lhs > rhs;
113             }
114 
115             template <typename T>
Validatedawn_native::__anondafefa560111::CheckLimit116             static MaybeError Validate(T supported, T required) {
117                 DAWN_INVALID_IF(IsBetter(required, supported),
118                                 "Required limit (%u) is greater than the supported limit (%u).",
119                                 required, supported);
120                 return {};
121             }
122         };
123 
124         template <typename T>
IsLimitUndefined(T value)125         bool IsLimitUndefined(T value) {
126             static_assert(sizeof(T) != sizeof(T), "IsLimitUndefined not implemented for this type");
127             return false;
128         }
129 
130         template <>
IsLimitUndefined(uint32_t value)131         bool IsLimitUndefined<uint32_t>(uint32_t value) {
132             return value == wgpu::kLimitU32Undefined;
133         }
134 
135         template <>
IsLimitUndefined(uint64_t value)136         bool IsLimitUndefined<uint64_t>(uint64_t value) {
137             return value == wgpu::kLimitU64Undefined;
138         }
139 
140     }  // namespace
141 
GetDefaultLimits(Limits * limits)142     void GetDefaultLimits(Limits* limits) {
143         ASSERT(limits != nullptr);
144 #define X(Better, limitName, base, ...) limits->limitName = base;
145         LIMITS(X)
146 #undef X
147     }
148 
ReifyDefaultLimits(const Limits & limits)149     Limits ReifyDefaultLimits(const Limits& limits) {
150         Limits out;
151 #define X(Better, limitName, base, ...)                                           \
152     if (IsLimitUndefined(limits.limitName) ||                                     \
153         CheckLimit<LimitBetterDirection::Better>::IsBetter(                       \
154             static_cast<decltype(limits.limitName)>(base), limits.limitName)) {   \
155         /* If the limit is undefined or the default is better, use the default */ \
156         out.limitName = base;                                                     \
157     } else {                                                                      \
158         out.limitName = limits.limitName;                                         \
159     }
160         LIMITS(X)
161 #undef X
162         return out;
163     }
164 
ValidateLimits(const Limits & supportedLimits,const Limits & requiredLimits)165     MaybeError ValidateLimits(const Limits& supportedLimits, const Limits& requiredLimits) {
166 #define X(Better, limitName, ...)                                                  \
167     if (!IsLimitUndefined(requiredLimits.limitName)) {                             \
168         DAWN_TRY_CONTEXT(CheckLimit<LimitBetterDirection::Better>::Validate(       \
169                              supportedLimits.limitName, requiredLimits.limitName), \
170                          "validating " #limitName);                                \
171     }
172         LIMITS(X)
173 #undef X
174         return {};
175     }
176 
ApplyLimitTiers(Limits limits)177     Limits ApplyLimitTiers(Limits limits) {
178 #define X_TIER_COUNT(Better, limitName, ...) , std::integer_sequence<uint64_t, __VA_ARGS__>{}.size()
179 #define GET_TIER_COUNT(LIMIT_GROUP) \
180     ReduceSameValue(std::integer_sequence<uint32_t LIMIT_GROUP(X_TIER_COUNT)>{})
181 
182 #define X_EACH_GROUP(LIMIT_GROUP)                                    \
183     {                                                                \
184         constexpr uint32_t kTierCount = GET_TIER_COUNT(LIMIT_GROUP); \
185         for (uint32_t i = kTierCount; i != 0; --i) {                 \
186             LIMIT_GROUP(X_CHECK_BETTER_AND_CLAMP)                    \
187             /* Limits fit in tier and have been clamped. Break. */   \
188             break;                                                   \
189         }                                                            \
190     }
191 
192 #define X_CHECK_BETTER_AND_CLAMP(Better, limitName, ...)                                       \
193     {                                                                                          \
194         constexpr std::array<decltype(Limits::limitName), kTierCount> tiers{__VA_ARGS__};      \
195         decltype(Limits::limitName) tierValue = tiers[i - 1];                                  \
196         if (CheckLimit<LimitBetterDirection::Better>::IsBetter(tierValue, limits.limitName)) { \
197             /* The tier is better. Go to the next tier. */                                     \
198             continue;                                                                          \
199         } else if (tierValue != limits.limitName) {                                            \
200             /* Better than the tier. Degrade |limits| to the tier. */                          \
201             limits.limitName = tiers[i - 1];                                                   \
202         }                                                                                      \
203     }
204 
205         LIMITS_EACH_GROUP(X_EACH_GROUP)
206 #undef X_CHECK_BETTER
207 #undef X_EACH_GROUP
208 #undef GET_TIER_COUNT
209 #undef X_TIER_COUNT
210         return limits;
211     }
212 
213 }  // namespace dawn_native
214