| // Copyright (c) 2018 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 LIBSPIRV_OPT_UPGRADE_MEMORY_MODEL_H_ |
| #define LIBSPIRV_OPT_UPGRADE_MEMORY_MODEL_H_ |
| |
| #include "pass.h" |
| |
| #include <functional> |
| #include <tuple> |
| |
| namespace spvtools { |
| namespace opt { |
| |
| // Hashing functor for the memoized result store. |
| struct CacheHash { |
| size_t operator()( |
| const std::pair<uint32_t, std::vector<uint32_t>>& item) const { |
| std::u32string to_hash; |
| to_hash.push_back(item.first); |
| for (auto i : item.second) to_hash.push_back(i); |
| return std::hash<std::u32string>()(to_hash); |
| } |
| }; |
| |
| // Upgrades the memory model from Logical GLSL450 to Logical VulkanKHR. |
| // |
| // This pass remove deprecated decorations (Volatile and Coherent) and replaces |
| // them with new flags on individual instructions. It adds the Output storage |
| // class semantic to control barriers in tessellation control shaders that have |
| // an access to Output memory. |
| class UpgradeMemoryModel : public Pass { |
| public: |
| const char* name() const override { return "upgrade-memory-model"; } |
| Status Process() override; |
| |
| private: |
| // Used to indicate whether the operation performs an availability or |
| // visibility operation. |
| enum OperationType { kVisibility, kAvailability }; |
| |
| // Used to indicate whether the instruction is a memory or image instruction. |
| enum InstructionType { kMemory, kImage }; |
| |
| // Modifies the OpMemoryModel to use VulkanKHR. Adds the Vulkan memory model |
| // capability and extension. |
| void UpgradeMemoryModelInstruction(); |
| |
| // Upgrades memory, image and barrier instructions. |
| // Memory and image instructions convert coherent and volatile decorations |
| // into flags on the instruction. Barriers in tessellation shaders get the |
| // output storage semantic if appropriate. |
| void UpgradeInstructions(); |
| |
| // Returns whether |id| is coherent and/or volatile. |
| std::tuple<bool, bool, SpvScope> GetInstructionAttributes(uint32_t id); |
| |
| // Traces |inst| to determine if it is coherent and/or volatile. |
| // |indices| tracks the access chain indices seen so far. |
| std::pair<bool, bool> TraceInstruction(Instruction* inst, |
| std::vector<uint32_t> indices, |
| std::unordered_set<uint32_t>* visited); |
| |
| // Return true if |inst| is decorated with |decoration|. |
| // If |inst| is decorated by member decorations then either |value| must |
| // match the index or |value| must be a maximum allowable value. The max |
| // value allows any element to match. |
| bool HasDecoration(const Instruction* inst, uint32_t value, |
| SpvDecoration decoration); |
| |
| // Returns whether |type_id| indexed via |indices| is coherent and/or |
| // volatile. |
| std::pair<bool, bool> CheckType(uint32_t type_id, |
| const std::vector<uint32_t>& indices); |
| |
| // Returns whether any type/element under |inst| is coherent and/or volatile. |
| std::pair<bool, bool> CheckAllTypes(const Instruction* inst); |
| |
| // Modifies the flags of |inst| to include the new flags for the Vulkan |
| // memory model. |operation_type| indicates whether flags should use |
| // MakeVisible or MakeAvailable variants. |inst_type| indicates whether the |
| // Pointer or Texel variants of flags should be used. |
| void UpgradeFlags(Instruction* inst, uint32_t in_operand, bool is_coherent, |
| bool is_volatile, OperationType operation_type, |
| InstructionType inst_type); |
| |
| // Returns the result id for a constant for |scope|. |
| uint32_t GetScopeConstant(SpvScope scope); |
| |
| // Returns the value of |index_inst|. |index_inst| must be an OpConstant of |
| // integer type.g |
| uint64_t GetIndexValue(Instruction* index_inst); |
| |
| // Removes coherent and volatile decorations. |
| void CleanupDecorations(); |
| |
| // For all tessellation control entry points, if there is an operation on |
| // Output storage class, then all barriers are modified to include the |
| // OutputMemoryKHR semantic. |
| void UpgradeBarriers(); |
| |
| // If the Vulkan memory model is specified, device scope actually means |
| // device scope. The memory scope must be modified to be QueueFamilyKHR |
| // scope. |
| void UpgradeMemoryScope(); |
| |
| // Returns true if |scope_id| is SpvScopeDevice. |
| bool IsDeviceScope(uint32_t scope_id); |
| |
| // Upgrades GLSL.std.450 modf and frexp. Both instructions are replaced with |
| // their struct versions. New extracts and a store are added in order to |
| // facilitate adding memory model flags. |
| void UpgradeExtInst(Instruction* modf); |
| |
| // Caches the result of TraceInstruction. For a given result id and set of |
| // indices, stores whether that combination is coherent and/or volatile. |
| std::unordered_map<std::pair<uint32_t, std::vector<uint32_t>>, |
| std::pair<bool, bool>, CacheHash> |
| cache_; |
| }; |
| } // namespace opt |
| } // namespace spvtools |
| #endif // LIBSPIRV_OPT_UPGRADE_MEMORY_MODEL_H_ |