|  | // Copyright 2020 The Tint Authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #ifndef SRC_TRANSFORM_FIRST_INDEX_OFFSET_H_ | 
|  | #define SRC_TRANSFORM_FIRST_INDEX_OFFSET_H_ | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | #include "src/ast/module.h" | 
|  | #include "src/ast/variable_decl_statement.h" | 
|  | #include "src/transform/transform.h" | 
|  |  | 
|  | namespace tint { | 
|  | namespace transform { | 
|  |  | 
|  | /// Adds firstVertex/Instance (injected via root constants) to | 
|  | /// vertex/instance_idx builtins. | 
|  | /// | 
|  | /// This transform assumes that Name transform has been run before. | 
|  | /// | 
|  | /// Unlike other APIs, D3D always starts vertex and instance numbering at 0, | 
|  | /// regardless of the firstVertex/Instance value specified. This transformer | 
|  | /// adds the value of firstVertex/Instance to each builtin. This action is | 
|  | /// performed by adding a new constant equal to original builtin + | 
|  | /// firstVertex/Instance to each function that references one of these builtins. | 
|  | /// | 
|  | /// Note that D3D does not have any semantics for firstVertex/Instance. | 
|  | /// Therefore, these values must by passed to the shader. | 
|  | /// | 
|  | /// Before: | 
|  | ///   [[builtin(vertex_index)]] var<in> vert_idx : u32; | 
|  | ///   fn func() -> u32 { | 
|  | ///     return vert_idx; | 
|  | ///   } | 
|  | /// | 
|  | /// After: | 
|  | ///   [[block]] | 
|  | ///   struct TintFirstIndexOffsetData { | 
|  | ///     [[offset(0)]] tint_first_vertex_index : u32; | 
|  | ///     [[offset(4)]] tint_first_instance_index : u32; | 
|  | ///   }; | 
|  | ///   [[builtin(vertex_index)]] var<in> tint_first_index_offset_vert_idx : u32; | 
|  | ///   [[binding(N), set(M)]] var<uniform> tint_first_index_data : | 
|  | ///                                                    TintFirstIndexOffsetData; | 
|  | ///   fn func() -> u32 { | 
|  | ///     const vert_idx = (tint_first_index_offset_vert_idx + | 
|  | ///                       tint_first_index_data.tint_first_vertex_index); | 
|  | ///     return vert_idx; | 
|  | ///   } | 
|  | /// | 
|  | class FirstIndexOffset : public Transform { | 
|  | public: | 
|  | /// Constructor | 
|  | /// @param binding the binding() for firstVertex/Instance uniform | 
|  | /// @param set the set() for firstVertex/Instance uniform | 
|  | FirstIndexOffset(uint32_t binding, uint32_t set); | 
|  | ~FirstIndexOffset() override; | 
|  |  | 
|  | /// Runs the transform on `module`, returning the transformation result. | 
|  | /// @note Users of Tint should register the transform with transform manager | 
|  | /// and invoke its Run(), instead of directly calling the transform's Run(). | 
|  | /// Calling Run() directly does not perform module state cleanup operations. | 
|  | /// @param module the source module to transform | 
|  | /// @returns the transformation result | 
|  | Output Run(ast::Module* module) override; | 
|  |  | 
|  | /// @returns whether shader uses vertex_index | 
|  | bool HasVertexIndex(); | 
|  |  | 
|  | /// @returns whether shader uses instance_index | 
|  | bool HasInstanceIndex(); | 
|  |  | 
|  | /// @returns offset of firstVertex into constant buffer | 
|  | uint32_t GetFirstVertexOffset(); | 
|  |  | 
|  | /// @returns offset of firstInstance into constant buffer | 
|  | uint32_t GetFirstInstanceOffset(); | 
|  |  | 
|  | private: | 
|  | /// Adds uniform buffer with firstVertex/Instance to module | 
|  | /// @returns variable of new uniform buffer | 
|  | ast::Variable* AddUniformBuffer(ast::Module* mod); | 
|  | /// Adds constant with modified original_name builtin to func | 
|  | /// @param original_name the name of the original builtin used in function | 
|  | /// @param field_name name of field in firstVertex/Instance buffer | 
|  | /// @param buffer_var variable of firstVertex/Instance buffer | 
|  | /// @param module the target module to contain the new ast nodes | 
|  | ast::VariableDeclStatement* CreateFirstIndexOffset( | 
|  | const std::string& original_name, | 
|  | const std::string& field_name, | 
|  | ast::Variable* buffer_var, | 
|  | ast::Module* module); | 
|  |  | 
|  | uint32_t binding_; | 
|  | uint32_t set_; | 
|  |  | 
|  | bool has_vertex_index_ = false; | 
|  | bool has_instance_index_ = false; | 
|  |  | 
|  | uint32_t vertex_index_offset_ = 0; | 
|  | uint32_t instance_index_offset_ = 0; | 
|  | }; | 
|  | }  // namespace transform | 
|  | }  // namespace tint | 
|  |  | 
|  | #endif  // SRC_TRANSFORM_FIRST_INDEX_OFFSET_H_ |