• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 Google LLC
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 SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
16 #define SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
17 
18 #include <memory>
19 #include <unordered_set>
20 #include <utility>
21 
22 #include "source/opt/pass.h"
23 #include "source/opt/types.h"
24 
25 namespace spvtools {
26 namespace opt {
27 
28 // A struct for a pair of descriptor set and binding.
29 struct DescriptorSetAndBinding {
30   uint32_t descriptor_set;
31   uint32_t binding;
32 
33   bool operator==(const DescriptorSetAndBinding& descriptor_set_binding) const {
34     return descriptor_set_binding.descriptor_set == descriptor_set &&
35            descriptor_set_binding.binding == binding;
36   }
37 };
38 
39 // See optimizer.hpp for documentation.
40 class ConvertToSampledImagePass : public Pass {
41  public:
42   // Hashing functor for the pair of descriptor set and binding.
43   struct DescriptorSetAndBindingHash {
operatorDescriptorSetAndBindingHash44     size_t operator()(
45         const DescriptorSetAndBinding& descriptor_set_binding) const {
46       return std::hash<uint32_t>()(descriptor_set_binding.descriptor_set) ^
47              std::hash<uint32_t>()(descriptor_set_binding.binding);
48     }
49   };
50 
51   using SetOfDescriptorSetAndBindingPairs =
52       std::unordered_set<DescriptorSetAndBinding, DescriptorSetAndBindingHash>;
53   using DescriptorSetBindingToInstruction =
54       std::unordered_map<DescriptorSetAndBinding, Instruction*,
55                          DescriptorSetAndBindingHash>;
56 
ConvertToSampledImagePass(const std::vector<DescriptorSetAndBinding> & descriptor_set_binding_pairs)57   explicit ConvertToSampledImagePass(
58       const std::vector<DescriptorSetAndBinding>& descriptor_set_binding_pairs)
59       : descriptor_set_binding_pairs_(descriptor_set_binding_pairs.begin(),
60                                       descriptor_set_binding_pairs.end()) {}
61 
name()62   const char* name() const override { return "convert-to-sampled-image"; }
63   Status Process() override;
64 
65   // Parses the given null-terminated C string to get a vector of descriptor set
66   // and binding pairs. Returns a unique pointer to the vector of descriptor set
67   // and binding pairs built from the given |str| on success. Returns a nullptr
68   // if the given string is not valid for building the vector of pairs.
69   // A valid string for building the vector of pairs should follow the rule
70   // below:
71   //
72   //  "<descriptor set>:<binding> <descriptor set>:<binding> ..."
73   //  Example:
74   //    "3:5 2:1 0:4"
75   //
76   //  Entries are separated with blank spaces (i.e.:' ', '\n', '\r', '\t',
77   //  '\f', '\v'). Each entry corresponds to a descriptor set and binding pair.
78   //  Multiple spaces between, before or after entries are allowed. However,
79   //  spaces are not allowed within a descriptor set or binding.
80   //
81   //  In each entry, the descriptor set and binding are separated by ':'.
82   //  Missing ':' in any entry is invalid. And it is invalid to have blank
83   //  spaces in between the descriptor set and ':' or ':' and the binding.
84   //
85   //  <descriptor set>: the descriptor set.
86   //    The text must represent a valid uint32_t number.
87   //
88   //  <binding>: the binding.
89   //    The text must represent a valid uint32_t number.
90   static std::unique_ptr<std::vector<DescriptorSetAndBinding>>
91   ParseDescriptorSetBindingPairsString(const char* str);
92 
93  private:
94   // Collects resources to convert to sampled image and saves them in
95   // |descriptor_set_binding_pair_to_sampler| if the resource is a sampler and
96   // saves them in |descriptor_set_binding_pair_to_image| if the resource is an
97   // image. Returns false if two samplers or two images have the same descriptor
98   // set and binding. Otherwise, returns true.
99   bool CollectResourcesToConvert(
100       DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_sampler,
101       DescriptorSetBindingToInstruction* descriptor_set_binding_pair_to_image)
102       const;
103 
104   // Finds an OpDecorate with DescriptorSet decorating |inst| and another
105   // OpDecorate with Binding decorating |inst|. Stores the descriptor set and
106   // binding in |descriptor_set_binding|. Returns whether it successfully finds
107   // the descriptor set and binding or not.
108   bool GetDescriptorSetBinding(
109       const Instruction& inst,
110       DescriptorSetAndBinding* descriptor_set_binding) const;
111 
112   // Returns whether |descriptor_set_binding| is a pair of a descriptor set
113   // and a binding that we have to convert resources with it to a sampled image
114   // or not.
115   bool ShouldResourceBeConverted(
116       const DescriptorSetAndBinding& descriptor_set_binding) const;
117 
118   // Returns the pointee type of the type of variable |variable|. If |variable|
119   // is not an OpVariable instruction, just returns nullptr.
120   const analysis::Type* GetVariableType(const Instruction& variable) const;
121 
122   // Returns the storage class of |variable|.
123   SpvStorageClass GetStorageClass(const Instruction& variable) const;
124 
125   // Finds |inst|'s users whose opcode is |user_opcode| or users of OpCopyObject
126   // instructions of |inst| whose opcode is |user_opcode| and puts them in
127   // |uses|.
128   void FindUses(const Instruction* inst, std::vector<Instruction*>* uses,
129                 uint32_t user_opcode) const;
130 
131   // Finds OpImage* instructions using |image| or OpCopyObject instructions that
132   // copy |image| and puts them in |uses|.
133   void FindUsesOfImage(const Instruction* image,
134                        std::vector<Instruction*>* uses) const;
135 
136   // Creates an OpImage instruction that extracts the image from the sampled
137   // image |sampled_image|.
138   Instruction* CreateImageExtraction(Instruction* sampled_image);
139 
140   // Converts |image_variable| whose type is an image pointer to sampled image
141   // type. Updates users of |image_variable| accordingly. If some instructions
142   // e.g., OpImageRead use |image_variable| as an Image operand, creates an
143   // image extracted from the sampled image using OpImage and replace the Image
144   // operands of the users with the extracted image. If some OpSampledImage
145   // instructions use |image_variable| and sampler whose descriptor set and
146   // binding are the same with |image_variable|, just combines |image_variable|
147   // and the sampler to a sampled image.
148   Pass::Status UpdateImageVariableToSampledImage(
149       Instruction* image_variable,
150       const DescriptorSetAndBinding& descriptor_set_binding);
151 
152   // Returns the id of type sampled image type whose image type is the one of
153   // |image_variable|.
154   uint32_t GetSampledImageTypeForImage(Instruction* image_variable);
155 
156   // Moves |inst| next to the OpType* instruction with |type_id|.
157   void MoveInstructionNextToType(Instruction* inst, uint32_t type_id);
158 
159   // Converts |image_variable| whose type is an image pointer to sampled image
160   // with the type id |sampled_image_type_id|. Returns whether it successfully
161   // converts the type of |image_variable| or not.
162   bool ConvertImageVariableToSampledImage(Instruction* image_variable,
163                                           uint32_t sampled_image_type_id);
164 
165   // Replaces |sampled_image_load| instruction used by OpImage* with the image
166   // extracted from |sampled_image_load|. Returns the extracted image or nullptr
167   // if it does not have uses.
168   Instruction* UpdateImageUses(Instruction* sampled_image_load);
169 
170   // Returns true if the sampler of |sampled_image_inst| is decorated by a
171   // descriptor set and a binding |descriptor_set_binding|.
172   bool IsSamplerOfSampledImageDecoratedByDescriptorSetBinding(
173       Instruction* sampled_image_inst,
174       const DescriptorSetAndBinding& descriptor_set_binding);
175 
176   // Replaces OpSampledImage instructions using |image_load| with |image_load|
177   // if the sampler of the OpSampledImage instruction has descriptor set and
178   // binding |image_descriptor_set_binding|. Otherwise, replaces |image_load|
179   // with |image_extraction|.
180   void UpdateSampledImageUses(
181       Instruction* image_load, Instruction* image_extraction,
182       const DescriptorSetAndBinding& image_descriptor_set_binding);
183 
184   // Checks the uses of |sampler_variable|. When a sampler is used by
185   // OpSampledImage instruction, the corresponding image must be
186   // |image_to_be_combined_with| that should be already converted to a sampled
187   // image by UpdateImageVariableToSampledImage() method.
188   Pass::Status CheckUsesOfSamplerVariable(
189       const Instruction* sampler_variable,
190       Instruction* image_to_be_combined_with);
191 
192   // Returns true if Image operand of |sampled_image_inst| is the image of
193   // |image_variable|.
194   bool DoesSampledImageReferenceImage(Instruction* sampled_image_inst,
195                                       Instruction* image_variable);
196 
197   // A set of pairs of descriptor set and binding. If an image and/or a sampler
198   // have a pair of descriptor set and binding that is an element of
199   // |descriptor_set_binding_pairs_|, they/it will be converted to a sampled
200   // image by this pass.
201   const SetOfDescriptorSetAndBindingPairs descriptor_set_binding_pairs_;
202 };
203 
204 }  // namespace opt
205 }  // namespace spvtools
206 
207 #endif  // SOURCE_OPT_CONVERT_TO_SAMPLED_IMAGE_PASS_H_
208