Skip to content

Commit

Permalink
[Vulkan] Shader memory export (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
Triang3l committed May 25, 2024
1 parent 210ac4b commit 3d30b2e
Show file tree
Hide file tree
Showing 8 changed files with 1,535 additions and 94 deletions.
90 changes: 90 additions & 0 deletions src/xenia/gpu/spirv_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,95 @@ spv::Id SpirvBuilder::IfBuilder::createMergePhi(spv::Id then_variable,
getElsePhiParent());
}

SpirvBuilder::SwitchBuilder::SwitchBuilder(spv::Id selector,
unsigned int selection_control,
SpirvBuilder& builder)
: builder_(builder),
selector_(selector),
selection_control_(selection_control),
function_(builder.getBuildPoint()->getParent()),
header_block_(builder.getBuildPoint()),
default_phi_parent_(builder.getBuildPoint()->getId()) {
merge_block_ = new spv::Block(builder_.getUniqueId(), function_);
}

void SpirvBuilder::SwitchBuilder::makeBeginDefault() {
assert_null(default_block_);

endSegment();

default_block_ = new spv::Block(builder_.getUniqueId(), function_);
function_.addBlock(default_block_);
default_block_->addPredecessor(header_block_);
builder_.setBuildPoint(default_block_);

current_branch_ = Branch::kDefault;
}

void SpirvBuilder::SwitchBuilder::makeBeginCase(unsigned int literal) {
endSegment();

auto case_block = new spv::Block(builder_.getUniqueId(), function_);
function_.addBlock(case_block);
cases_.emplace_back(literal, case_block->getId());
case_block->addPredecessor(header_block_);
builder_.setBuildPoint(case_block);

current_branch_ = Branch::kCase;
}

void SpirvBuilder::SwitchBuilder::addCurrentCaseLiteral(unsigned int literal) {
assert_true(current_branch_ == Branch::kCase);

cases_.emplace_back(literal, cases_.back().second);
}

void SpirvBuilder::SwitchBuilder::makeEndSwitch() {
endSegment();

builder_.setBuildPoint(header_block_);

builder_.createSelectionMerge(merge_block_, selection_control_);

std::unique_ptr<spv::Instruction> switch_instruction =
std::make_unique<spv::Instruction>(spv::OpSwitch);
switch_instruction->addIdOperand(selector_);
if (default_block_) {
switch_instruction->addIdOperand(default_block_->getId());
} else {
switch_instruction->addIdOperand(merge_block_->getId());
merge_block_->addPredecessor(header_block_);
}
for (const std::pair<unsigned int, spv::Id>& case_pair : cases_) {
switch_instruction->addImmediateOperand(case_pair.first);
switch_instruction->addIdOperand(case_pair.second);
}
builder_.getBuildPoint()->addInstruction(std::move(switch_instruction));

function_.addBlock(merge_block_);
builder_.setBuildPoint(merge_block_);

current_branch_ = Branch::kMerge;
}

void SpirvBuilder::SwitchBuilder::endSegment() {
assert_true(current_branch_ == Branch::kSelection ||
current_branch_ == Branch::kDefault ||
current_branch_ == Branch::kCase);

if (current_branch_ == Branch::kSelection) {
return;
}

if (!builder_.getBuildPoint()->isTerminated()) {
builder_.createBranch(merge_block_);
if (current_branch_ == Branch::kDefault) {
default_phi_parent_ = builder_.getBuildPoint()->getId();
}
}

current_branch_ = Branch::kSelection;
}

} // namespace gpu
} // namespace xe
47 changes: 47 additions & 0 deletions src/xenia/gpu/spirv_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
#ifndef XENIA_GPU_SPIRV_BUILDER_H_
#define XENIA_GPU_SPIRV_BUILDER_H_

#include <memory>
#include <optional>
#include <utility>
#include <vector>

#include "third_party/glslang/SPIRV/SpvBuilder.h"
#include "xenia/base/assert.h"
Expand Down Expand Up @@ -99,6 +102,50 @@ class SpirvBuilder : public spv::Builder {
Branch currentBranch = Branch::kThen;
#endif
};

// Simpler and more flexible (such as multiple cases pointing to the same
// block) compared to makeSwitch.
class SwitchBuilder {
public:
SwitchBuilder(spv::Id selector, unsigned int selection_control,
SpirvBuilder& builder);
~SwitchBuilder() { assert_true(current_branch_ == Branch::kMerge); }

void makeBeginDefault();
void makeBeginCase(unsigned int literal);
void addCurrentCaseLiteral(unsigned int literal);
void makeEndSwitch();

// If there's no default block that branches to the merge block, the phi
// parent is the header block - this simplifies case-only usage.
spv::Id getDefaultPhiParent() const { return default_phi_parent_; }

private:
enum class Branch {
kSelection,
kDefault,
kCase,
kMerge,
};

void endSegment();

SpirvBuilder& builder_;
spv::Id selector_;
unsigned int selection_control_;

spv::Function& function_;

spv::Block* header_block_;
spv::Block* merge_block_;
spv::Block* default_block_ = nullptr;

std::vector<std::pair<unsigned int, spv::Id>> cases_;

spv::Id default_phi_parent_;

Branch current_branch_ = Branch::kSelection;
};
};

} // namespace gpu
Expand Down
Loading

0 comments on commit 3d30b2e

Please sign in to comment.