Skip to content

Commit 3d30b2e

Browse files
committed
[Vulkan] Shader memory export (#145)
1 parent 210ac4b commit 3d30b2e

File tree

8 files changed

+1535
-94
lines changed

8 files changed

+1535
-94
lines changed

src/xenia/gpu/spirv_builder.cc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,95 @@ spv::Id SpirvBuilder::IfBuilder::createMergePhi(spv::Id then_variable,
203203
getElsePhiParent());
204204
}
205205

206+
SpirvBuilder::SwitchBuilder::SwitchBuilder(spv::Id selector,
207+
unsigned int selection_control,
208+
SpirvBuilder& builder)
209+
: builder_(builder),
210+
selector_(selector),
211+
selection_control_(selection_control),
212+
function_(builder.getBuildPoint()->getParent()),
213+
header_block_(builder.getBuildPoint()),
214+
default_phi_parent_(builder.getBuildPoint()->getId()) {
215+
merge_block_ = new spv::Block(builder_.getUniqueId(), function_);
216+
}
217+
218+
void SpirvBuilder::SwitchBuilder::makeBeginDefault() {
219+
assert_null(default_block_);
220+
221+
endSegment();
222+
223+
default_block_ = new spv::Block(builder_.getUniqueId(), function_);
224+
function_.addBlock(default_block_);
225+
default_block_->addPredecessor(header_block_);
226+
builder_.setBuildPoint(default_block_);
227+
228+
current_branch_ = Branch::kDefault;
229+
}
230+
231+
void SpirvBuilder::SwitchBuilder::makeBeginCase(unsigned int literal) {
232+
endSegment();
233+
234+
auto case_block = new spv::Block(builder_.getUniqueId(), function_);
235+
function_.addBlock(case_block);
236+
cases_.emplace_back(literal, case_block->getId());
237+
case_block->addPredecessor(header_block_);
238+
builder_.setBuildPoint(case_block);
239+
240+
current_branch_ = Branch::kCase;
241+
}
242+
243+
void SpirvBuilder::SwitchBuilder::addCurrentCaseLiteral(unsigned int literal) {
244+
assert_true(current_branch_ == Branch::kCase);
245+
246+
cases_.emplace_back(literal, cases_.back().second);
247+
}
248+
249+
void SpirvBuilder::SwitchBuilder::makeEndSwitch() {
250+
endSegment();
251+
252+
builder_.setBuildPoint(header_block_);
253+
254+
builder_.createSelectionMerge(merge_block_, selection_control_);
255+
256+
std::unique_ptr<spv::Instruction> switch_instruction =
257+
std::make_unique<spv::Instruction>(spv::OpSwitch);
258+
switch_instruction->addIdOperand(selector_);
259+
if (default_block_) {
260+
switch_instruction->addIdOperand(default_block_->getId());
261+
} else {
262+
switch_instruction->addIdOperand(merge_block_->getId());
263+
merge_block_->addPredecessor(header_block_);
264+
}
265+
for (const std::pair<unsigned int, spv::Id>& case_pair : cases_) {
266+
switch_instruction->addImmediateOperand(case_pair.first);
267+
switch_instruction->addIdOperand(case_pair.second);
268+
}
269+
builder_.getBuildPoint()->addInstruction(std::move(switch_instruction));
270+
271+
function_.addBlock(merge_block_);
272+
builder_.setBuildPoint(merge_block_);
273+
274+
current_branch_ = Branch::kMerge;
275+
}
276+
277+
void SpirvBuilder::SwitchBuilder::endSegment() {
278+
assert_true(current_branch_ == Branch::kSelection ||
279+
current_branch_ == Branch::kDefault ||
280+
current_branch_ == Branch::kCase);
281+
282+
if (current_branch_ == Branch::kSelection) {
283+
return;
284+
}
285+
286+
if (!builder_.getBuildPoint()->isTerminated()) {
287+
builder_.createBranch(merge_block_);
288+
if (current_branch_ == Branch::kDefault) {
289+
default_phi_parent_ = builder_.getBuildPoint()->getId();
290+
}
291+
}
292+
293+
current_branch_ = Branch::kSelection;
294+
}
295+
206296
} // namespace gpu
207297
} // namespace xe

src/xenia/gpu/spirv_builder.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
#ifndef XENIA_GPU_SPIRV_BUILDER_H_
1111
#define XENIA_GPU_SPIRV_BUILDER_H_
1212

13+
#include <memory>
1314
#include <optional>
15+
#include <utility>
16+
#include <vector>
1417

1518
#include "third_party/glslang/SPIRV/SpvBuilder.h"
1619
#include "xenia/base/assert.h"
@@ -99,6 +102,50 @@ class SpirvBuilder : public spv::Builder {
99102
Branch currentBranch = Branch::kThen;
100103
#endif
101104
};
105+
106+
// Simpler and more flexible (such as multiple cases pointing to the same
107+
// block) compared to makeSwitch.
108+
class SwitchBuilder {
109+
public:
110+
SwitchBuilder(spv::Id selector, unsigned int selection_control,
111+
SpirvBuilder& builder);
112+
~SwitchBuilder() { assert_true(current_branch_ == Branch::kMerge); }
113+
114+
void makeBeginDefault();
115+
void makeBeginCase(unsigned int literal);
116+
void addCurrentCaseLiteral(unsigned int literal);
117+
void makeEndSwitch();
118+
119+
// If there's no default block that branches to the merge block, the phi
120+
// parent is the header block - this simplifies case-only usage.
121+
spv::Id getDefaultPhiParent() const { return default_phi_parent_; }
122+
123+
private:
124+
enum class Branch {
125+
kSelection,
126+
kDefault,
127+
kCase,
128+
kMerge,
129+
};
130+
131+
void endSegment();
132+
133+
SpirvBuilder& builder_;
134+
spv::Id selector_;
135+
unsigned int selection_control_;
136+
137+
spv::Function& function_;
138+
139+
spv::Block* header_block_;
140+
spv::Block* merge_block_;
141+
spv::Block* default_block_ = nullptr;
142+
143+
std::vector<std::pair<unsigned int, spv::Id>> cases_;
144+
145+
spv::Id default_phi_parent_;
146+
147+
Branch current_branch_ = Branch::kSelection;
148+
};
102149
};
103150

104151
} // namespace gpu

0 commit comments

Comments
 (0)