1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// Copyright (c) 2025 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_SPLIT_COMBINED_IMAGE_SAMPLER_PASS_H_
#define LIBSPIRV_OPT_SPLIT_COMBINED_IMAGE_SAMPLER_PASS_H_
#include <unordered_map>
#include <utility>
#include <vector>
#include "source/diagnostic.h"
#include "source/opt/decoration_manager.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/pass.h"
#include "source/opt/type_manager.h"
namespace spvtools {
namespace opt {
// Replaces each combined-image sampler variable with an image variable
// and a sampler variable. Similar for function parameters.
//
// Copy the descriptor set and binding number. Vulkan allows this, surprisingly.
class SplitCombinedImageSamplerPass : public Pass {
public:
virtual ~SplitCombinedImageSamplerPass() override = default;
const char* name() const override { return "split-combined-image-sampler"; }
IRContext::Analysis GetPreservedAnalyses() override;
Status Process() override;
private:
// Records failure for the current module, and returns a stream
// that can be used to provide user error information to the message
// consumer.
spvtools::DiagnosticStream Fail();
// Find variables that contain combined texture-samplers, or arrays of them.
// Also populate known_globals_.
void FindCombinedTextureSamplers();
// Returns the sampler type. If it does not yet exist, then it is created
// and placed before the first sampled image type.
Instruction* GetSamplerType();
// Remaps function types and function declarations. Each
// pointer-to-sampled-image-type operand is replaced with a pair of
// pointer-to-image-type and pointer-to-sampler-type pair.
// Updates the def-use manager and type manager.
spv_result_t RemapFunctions();
// Remap resource variables.
// Updates the def-use manager.
spv_result_t RemapVars();
// Remap a single resource variable for combined var.
// Updates the def-use manager and the decorations manager.
spv_result_t RemapVar(Instruction* combined_var);
// Transitively remaps uses of the combined object with uses of the
// decomposed image and sampler parts. The combined object can be sampled
// image value, a pointer to one, an array of one, or a pointer to an array
// of one. The image and sampler parts have corresponding shapes.
// Updates the def-use manager and the decorations manager.
spv_result_t RemapUses(Instruction* combined, Instruction* image_part,
Instruction* sampler_part);
// Removes types that are no longer referenced.
spv_result_t RemoveDeadTypes();
// Returns the type instruction for a UniformConstant pointer to the given
// pointee type. If it does not yet exist, the new type instruction is created
// and placed immediately after the pointee type instruction. Updates def-use
// and type managers, and the set of known globals.
Instruction* MakeUniformConstantPointer(Instruction* pointee);
// Returns the ID of the pointee type for a pointer value instruction.
uint32_t PointeeTypeId(Instruction* ptr_value) {
auto* ptr_ty = def_use_mgr_->GetDef(ptr_value->type_id());
assert(ptr_ty->opcode() == spv::Op::OpTypePointer);
return ptr_ty->GetSingleWordInOperand(1);
}
// Creates a new OpName instruction mapping the given name to the given
// string, and adds it to the module at the end of the OpName and OpMemberName
// section.
void AddOpName(uint32_t id, const std::string& name);
// Cached from the IRContext. Valid while Process() is running.
analysis::DefUseManager* def_use_mgr_ = nullptr;
// Cached from the IRContext. Valid while Process() is running.
analysis::TypeManager* type_mgr_ = nullptr;
// Did processing modify the module?
bool modified_ = false;
Pass::Status Ok() {
return modified_ ? Pass::Status::SuccessWithChange
: Pass::Status::SuccessWithoutChange;
}
// The first OpTypeSampledImage instruction in the module, if one exists.
Instruction* first_sampled_image_type_ = nullptr;
// An OpTypeSampler instruction, if one existed already, or if we created one.
Instruction* sampler_type_ = nullptr;
// The known types and module-scope values.
// We use this to know when a new such value was created.
std::unordered_set<uint32_t> known_globals_;
bool IsKnownGlobal(uint32_t id) const {
return known_globals_.find(id) != known_globals_.end();
}
void RegisterGlobal(uint32_t id) { known_globals_.insert(id); }
void RegisterNewGlobal(uint32_t id) {
modified_ = true;
RegisterGlobal(id);
}
// Deletes an instruction and associated debug and decoration instructions.
// Updates the def-use manager.
void KillInst(Instruction* inst);
// Combined types. The known combined sampled-image type,
// and recursively pointers or arrays of them.
std::unordered_set<uint32_t> combined_types_;
// The pre-existing types this pass should remove: pointer to
// combined type, array of combined type, pointer to array of combined type.
std::vector<uint32_t> combined_types_to_remove_;
// Is an OpTypeSampledImage used as a function parameter? Those should be
// transformed.
bool sampled_image_used_as_param_ = false;
// Remaps a combined-kind type to corresponding sampler-kind and image-kind
// of type.
struct TypeRemapInfo {
// The instruction for the combined type, pointer to combined type,
// or point to array of combined type.
Instruction* combined_kind_type;
// The corresponding image type, with the same shape of indirection as the
// combined_kind_type.
Instruction* image_kind_type;
// The corresponding sampler type, with the same shape of indirection as the
// combined_kind_type.
Instruction* sampler_kind_type;
};
// Maps the ID of a combined-image-sampler type kind to its corresponding
// split parts.
std::unordered_map<uint32_t, TypeRemapInfo> type_remap_;
// Returns the image-like and sampler-like types of the same indirection shape
// as the given combined-like type. If combined_kind_type is not a combined
// type or a pointer to one, or an array of one or a pointer to an array of
// one, then returns a pair of null pointer. Either both components are
// non-null, or both components are null. Updates the def-use manager and the
// type manager if new instructions are created.
std::pair<Instruction*, Instruction*> SplitType(
Instruction& combined_kind_type);
// The combined-image-sampler variables to be replaced.
std::vector<Instruction*> ordered_vars_;
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_SPLIT_COMBINED_IMAGE_SAMPLER_PASS_H_
|