mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-28 22:21:03 +00:00
d35a78db57
Fixes #4960 * Switches to using enum classes with an underlying type to avoid undefined behaviour
208 lines
9.2 KiB
C++
208 lines
9.2 KiB
C++
// 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 <memory>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
|
|
#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<uint32_t>()(descriptor_set_binding.descriptor_set) ^
|
|
std::hash<uint32_t>()(descriptor_set_binding.binding);
|
|
}
|
|
};
|
|
|
|
using SetOfDescriptorSetAndBindingPairs =
|
|
std::unordered_set<DescriptorSetAndBinding, DescriptorSetAndBindingHash>;
|
|
using DescriptorSetBindingToInstruction =
|
|
std::unordered_map<DescriptorSetAndBinding, Instruction*,
|
|
DescriptorSetAndBindingHash>;
|
|
|
|
explicit ConvertToSampledImagePass(
|
|
const std::vector<DescriptorSetAndBinding>& 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:
|
|
//
|
|
// "<descriptor set>:<binding> <descriptor set>:<binding> ..."
|
|
// 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.
|
|
//
|
|
// <descriptor set>: the descriptor set.
|
|
// The text must represent a valid uint32_t number.
|
|
//
|
|
// <binding>: the binding.
|
|
// The text must represent a valid uint32_t number.
|
|
static std::unique_ptr<std::vector<DescriptorSetAndBinding>>
|
|
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<Instruction*>* 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<Instruction*>* 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_
|