• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint 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 #ifndef FUZZERS_TRANSFORM_BUILDER_H_
16 #define FUZZERS_TRANSFORM_BUILDER_H_
17 
18 #include <string>
19 #include <vector>
20 
21 #include "include/tint/tint.h"
22 
23 #include "fuzzers/data_builder.h"
24 
25 namespace tint {
26 namespace fuzzers {
27 
28 /// Fuzzer utility class to build inputs for transforms and setup the transform
29 /// manager.
30 class TransformBuilder {
31  public:
32   /// @brief Initializes the internal builder using a seed value
33   /// @param seed - seed value passed to engine
TransformBuilder(uint64_t seed)34   explicit TransformBuilder(uint64_t seed) : builder_(seed) {}
35 
36   /// @brief Initializes the internal builder using seed data
37   /// @param data - data fuzzer to calculate seed from
38   /// @param size - size of data buffer
TransformBuilder(const uint8_t * data,size_t size)39   explicit TransformBuilder(const uint8_t* data, size_t size)
40       : builder_(data, size) {
41     assert(data != nullptr && "|data| must be !nullptr");
42   }
43 
44   ~TransformBuilder() = default;
45 
manager()46   transform::Manager* manager() { return &manager_; }
data_map()47   transform::DataMap* data_map() { return &data_map_; }
48 
49   /// Adds a transform and needed data to |manager_| and |data_map_|.
50   /// @tparam T - A class that inherits from transform::Transform and has an
51   ///             explicit specialization in AddTransformImpl.
52   template <typename T>
AddTransform()53   void AddTransform() {
54     static_assert(std::is_base_of<transform::Transform, T>::value,
55                   "T is not a transform::Transform");
56     AddTransformImpl<T>::impl(this);
57   }
58 
59   /// Helper that invokes Add*Transform for all of the platform independent
60   /// passes.
AddPlatformIndependentPasses()61   void AddPlatformIndependentPasses() {
62     AddTransform<transform::Robustness>();
63     AddTransform<transform::FirstIndexOffset>();
64     AddTransform<transform::BindingRemapper>();
65     AddTransform<transform::Renamer>();
66     AddTransform<transform::SingleEntryPoint>();
67     AddTransform<transform::VertexPulling>();
68   }
69 
70  private:
71   DataBuilder builder_;
72   transform::Manager manager_;
73   transform::DataMap data_map_;
74 
builder()75   DataBuilder* builder() { return &builder_; }
76 
77   /// Implementation of AddTransform, specialized for each transform that is
78   /// implemented. Default implementation intentionally deleted to cause compile
79   /// error if unimplemented type passed in.
80   /// @tparam T - A fuzzer transform
81   template <typename T>
82   struct AddTransformImpl;
83 
84   /// Implementation of AddTransform for transform::Robustness
85   template <>
86   struct AddTransformImpl<transform::Robustness> {
87     /// Add instance of transform::Robustness to TransformBuilder
88     /// @param tb - TransformBuilder to add transform to
89     static void impl(TransformBuilder* tb) {
90       tb->manager()->Add<transform::Robustness>();
91     }
92   };
93 
94   /// Implementation of AddTransform for transform::FirstIndexOffset
95   template <>
96   struct AddTransformImpl<transform::FirstIndexOffset> {
97     /// Add instance of transform::FirstIndexOffset to TransformBuilder
98     /// @param tb - TransformBuilder to add transform to
99     static void impl(TransformBuilder* tb) {
100       struct Config {
101         uint32_t group;
102         uint32_t binding;
103       };
104 
105       Config config = tb->builder()->build<Config>();
106 
107       tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(
108           config.binding, config.group);
109       tb->manager()->Add<transform::FirstIndexOffset>();
110     }
111   };
112 
113   /// Implementation of AddTransform for transform::BindingRemapper
114   template <>
115   struct AddTransformImpl<transform::BindingRemapper> {
116     /// Add instance of transform::BindingRemapper to TransformBuilder
117     /// @param tb - TransformBuilder to add transform to
118     static void impl(TransformBuilder* tb) {
119       struct Config {
120         uint8_t old_group;
121         uint8_t old_binding;
122         uint8_t new_group;
123         uint8_t new_binding;
124         ast::Access new_access;
125       };
126 
127       std::vector<Config> configs = tb->builder()->vector<Config>();
128       transform::BindingRemapper::BindingPoints binding_points;
129       transform::BindingRemapper::AccessControls accesses;
130       for (const auto& config : configs) {
131         binding_points[{config.old_binding, config.old_group}] = {
132             config.new_binding, config.new_group};
133         accesses[{config.old_binding, config.old_group}] = config.new_access;
134       }
135 
136       tb->data_map()->Add<transform::BindingRemapper::Remappings>(
137           binding_points, accesses, tb->builder()->build<bool>());
138       tb->manager()->Add<transform::BindingRemapper>();
139     }
140   };
141 
142   /// Implementation of AddTransform for transform::Renamer
143   template <>
144   struct AddTransformImpl<transform::Renamer> {
145     /// Add instance of transform::Renamer to TransformBuilder
146     /// @param tb - TransformBuilder to add transform to
147     static void impl(TransformBuilder* tb) {
148       tb->manager()->Add<transform::Renamer>();
149     }
150   };
151 
152   /// Implementation of AddTransform for transform::SingleEntryPoint
153   template <>
154   struct AddTransformImpl<transform::SingleEntryPoint> {
155     /// Add instance of transform::SingleEntryPoint to TransformBuilder
156     /// @param tb - TransformBuilder to add transform to
157     static void impl(TransformBuilder* tb) {
158       auto input = tb->builder()->build<std::string>();
159       transform::SingleEntryPoint::Config cfg(input);
160 
161       tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
162       tb->manager()->Add<transform::SingleEntryPoint>();
163     }
164   };  // struct AddTransformImpl<transform::SingleEntryPoint>
165 
166   /// Implementation of AddTransform for transform::VertexPulling
167   template <>
168   struct AddTransformImpl<transform::VertexPulling> {
169     /// Add instance of transform::VertexPulling to TransformBuilder
170     /// @param tb - TransformBuilder to add transform to
171     static void impl(TransformBuilder* tb) {
172       transform::VertexPulling::Config cfg;
173       cfg.entry_point_name = tb->builder()->build<std::string>();
174       cfg.vertex_state =
175           tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
176               GenerateVertexBufferLayoutDescriptor);
177       cfg.pulling_group = tb->builder()->build<uint32_t>();
178 
179       tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
180       tb->manager()->Add<transform::VertexPulling>();
181     }
182 
183    private:
184     /// Generate an instance of transform::VertexAttributeDescriptor
185     /// @param b - DataBuilder to use
186     static transform::VertexAttributeDescriptor
187     GenerateVertexAttributeDescriptor(DataBuilder* b) {
188       transform::VertexAttributeDescriptor desc{};
189       desc.format = b->enum_class<transform::VertexFormat>(
190           static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
191       desc.offset = b->build<uint32_t>();
192       desc.shader_location = b->build<uint32_t>();
193       return desc;
194     }
195 
196     /// Generate an instance of VertexBufferLayoutDescriptor
197     /// @param b - DataBuilder to use
198     static transform::VertexBufferLayoutDescriptor
199     GenerateVertexBufferLayoutDescriptor(DataBuilder* b) {
200       transform::VertexBufferLayoutDescriptor desc;
201       desc.array_stride = b->build<uint32_t>();
202       desc.step_mode = b->enum_class<transform::VertexStepMode>(
203           static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
204       desc.attributes = b->vector<transform::VertexAttributeDescriptor>(
205           GenerateVertexAttributeDescriptor);
206       return desc;
207     }
208   };
209 };  // class TransformBuilder
210 
211 }  // namespace fuzzers
212 }  // namespace tint
213 
214 #endif  // FUZZERS_TRANSFORM_BUILDER_H_
215