File: split_combined_image_sampler_pass.h

package info (click to toggle)
spirv-tools 2026.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 28,900 kB
  • sloc: cpp: 477,281; javascript: 5,908; python: 3,326; ansic: 488; sh: 450; ruby: 88; makefile: 18; lisp: 9
file content (169 lines) | stat: -rw-r--r-- 7,193 bytes parent folder | download | duplicates (13)
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_