// Copyright (c) 2021 Google LLC // // 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 SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ #define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_ #include #include #include #include "source/opt/pass.h" #include "source/opt/types.h" namespace spvtools { namespace opt { // A struct for a pair of descriptor set and binding. struct DescriptorSetAndBinding { uint32_t descriptor_set; uint32_t binding; bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const { return descriptor_set_binding.descriptor_set == descriptor_set && descriptor_set_binding.binding == binding; } }; // See optimizer.hpp for documentation. class ConvertToSampledImagePass : public Pass { public: // Hashing functor for the pair of descriptor set and binding. struct DescriptorSetAndBindingHash { size_t operator()( const DescriptorSetAndBinding& descriptor_set_binding) const { return std::hash()(descriptor_set_binding.descriptor_set) ^ std::hash()(descriptor_set_binding.binding); } }; using SetOfDescriptorSetAndBindingPairs = std::unordered_set; using DescriptorSetBindingToInstruction = std::unordered_map; explicit ConvertToSampledImagePass( const std::vector& descriptor_set_binding_pairs) : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(), descriptor_set_binding_pairs.end()) {} const char* name() const override { return "convert-to-sampled-image"; } Status Process() override; // Parses the given null-terminated C string to get a vector of descriptor set // and binding pairs. Returns a unique pointer to the vector of descriptor set // and binding pairs built from the given |str| on success. Returns a nullptr // if the given string is not valid for building the vector of pairs. // A valid string for building the vector of pairs should follow the rule // below: // // ": : ..." // Example: // "3:5 2:1 0:4" // // Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t', // '\f', '\v'). Each entry corresponds to a descriptor set and binding pair. // Multiple spaces between, before or after entries are allowed. However, // spaces are not allowed within a descriptor set or binding. // // In each entry, the descriptor set and binding are separated by ':'. // Missing ':' in any entry is invalid. And it is invalid to have blank // spaces in between the descriptor set and ':' or ':' and the binding. // // : the descriptor set. // The text must represent a valid uint32_t number. // // : the binding. // The text must represent a valid uint32_t number. static std::unique_ptr> ParseDescriptorSetBindingPairsString(const char* str); private: // Collects resources to convert to sampled image and saves them in // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and // saves them in |descriptor_set_binding_pair_to_image| if the resource is an // image. Returns false if two samplers or two images have the same descriptor // set and binding. Otherwise, returns true. bool CollectResourcesToConvert( DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler, DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image) const; // Finds an OpDecorate with DescriptorSet decorating |inst| and another // OpDecorate with Binding decorating |inst|. Stores the descriptor set and // binding in |descriptor_set_binding|. Returns whether it successfully finds // the descriptor set and binding or not. bool GetDescriptorSetBinding( const Instruction& inst, DescriptorSetAndBinding* descriptor_set_binding) const; // Returns whether |descriptor_set_binding| is a pair of a descriptor set // and a binding that we have to convert resources with it to a sampled image // or not. bool ShouldResourceBeConverted( const DescriptorSetAndBinding& descriptor_set_binding) const; // Returns the pointee type of the type of variable |variable|. If |variable| // is not an OpVariable instruction, just returns nullptr. const analysis::Type* GetVariableType(const Instruction& variable) const; // Returns the storage class of |variable|. spv::StorageClass GetStorageClass(const Instruction& variable) const; // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject // instructions of |inst| whose opcode is |user_opcode| and puts them in // |uses|. void FindUses(const Instruction* inst, std::vector* uses, spv::Op user_opcode) const; // Finds OpImage* instructions using |image| or OpCopyObject instructions that // copy |image| and puts them in |uses|. void FindUsesOfImage(const Instruction* image, std::vector* uses) const; // Creates an OpImage instruction that extracts the image from the sampled // image |sampled_image|. Instruction* CreateImageExtraction(Instruction* sampled_image); // Converts |image_variable| whose type is an image pointer to sampled image // type. Updates users of |image_variable| accordingly. If some instructions // e.g., OpImageRead use |image_variable| as an Image operand, creates an // image extracted from the sampled image using OpImage and replace the Image // operands of the users with the extracted image. If some OpSampledImage // instructions use |image_variable| and sampler whose descriptor set and // binding are the same with |image_variable|, just combines |image_variable| // and the sampler to a sampled image. Pass::Status UpdateImageVariableToSampledImage( Instruction* image_variable, const DescriptorSetAndBinding& descriptor_set_binding); // Returns the id of type sampled image type whose image type is the one of // |image_variable|. uint32_t GetSampledImageTypeForImage(Instruction* image_variable); // Moves |inst| next to the OpType* instruction with |type_id|. void MoveInstructionNextToType(Instruction* inst, uint32_t type_id); // Converts |image_variable| whose type is an image pointer to sampled image // with the type id |sampled_image_type_id|. Returns whether it successfully // converts the type of |image_variable| or not. bool ConvertImageVariableToSampledImage(Instruction* image_variable, uint32_t sampled_image_type_id); // Replaces |sampled_image_load| instruction used by OpImage* with the image // extracted from |sampled_image_load|. Returns the extracted image or nullptr // if it does not have uses. Instruction* UpdateImageUses(Instruction* sampled_image_load); // Returns true if the sampler of |sampled_image_inst| is decorated by a // descriptor set and a binding |descriptor_set_binding|. bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding( Instruction* sampled_image_inst, const DescriptorSetAndBinding& descriptor_set_binding); // Replaces OpSampledImage instructions using |image_load| with |image_load| // if the sampler of the OpSampledImage instruction has descriptor set and // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load| // with |image_extraction|. void UpdateSampledImageUses( Instruction* image_load, Instruction* image_extraction, const DescriptorSetAndBinding& image_descriptor_set_binding); // Checks the uses of |sampler_variable|. When a sampler is used by // OpSampledImage instruction, the corresponding image must be // |image_to_be_combined_with| that should be already converted to a sampled // image by UpdateImageVariableToSampledImage() method. Pass::Status CheckUsesOfSamplerVariable( const Instruction* sampler_variable, Instruction* image_to_be_combined_with); // Returns true if Image operand of |sampled_image_inst| is the image of // |image_variable|. bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst, Instruction* image_variable); // A set of pairs of descriptor set and binding. If an image and/or a sampler // have a pair of descriptor set and binding that is an element of // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled // image by this pass. const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_; }; } // namespace opt } // namespace spvtools #endif // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_