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