summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/ir_opt/layer_pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/ir_opt/layer_pass.cpp68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/shader_recompiler/ir_opt/layer_pass.cpp b/src/shader_recompiler/ir_opt/layer_pass.cpp
new file mode 100644
index 000000000..4574f7cf2
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/layer_pass.cpp
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <algorithm>
+#include <bit>
+#include <optional>
+
+#include <boost/container/small_vector.hpp>
+
+#include "shader_recompiler/environment.h"
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/ir/breadth_first_search.h"
+#include "shader_recompiler/frontend/ir/ir_emitter.h"
+#include "shader_recompiler/host_translate_info.h"
+#include "shader_recompiler/ir_opt/passes.h"
+#include "shader_recompiler/shader_info.h"
+
+namespace Shader::Optimization {
+
+static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) {
+ for (u32 i = 0; i < 32; i++) {
+ if (!stores.Generic(i)) {
+ return IR::Attribute::Generic0X + (i * 4);
+ }
+ }
+ return IR::Attribute::Layer;
+}
+
+static bool PermittedProgramStage(Stage stage) {
+ switch (stage) {
+ case Stage::VertexA:
+ case Stage::VertexB:
+ case Stage::TessellationControl:
+ case Stage::TessellationEval:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) {
+ if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) {
+ return;
+ }
+
+ const auto end{program.post_order_blocks.end()};
+ const auto layer_attribute = EmulatedLayerAttribute(program.info.stores);
+ bool requires_layer_emulation = false;
+
+ for (auto block = program.post_order_blocks.begin(); block != end; ++block) {
+ for (IR::Inst& inst : (*block)->Instructions()) {
+ if (inst.GetOpcode() == IR::Opcode::SetAttribute &&
+ inst.Arg(0).Attribute() == IR::Attribute::Layer) {
+ requires_layer_emulation = true;
+ inst.SetArg(0, IR::Value{layer_attribute});
+ }
+ }
+ }
+
+ if (requires_layer_emulation) {
+ program.info.requires_layer_emulation = true;
+ program.info.emulated_layer = layer_attribute;
+ program.info.stores.Set(IR::Attribute::Layer, false);
+ program.info.stores.Set(layer_attribute, true);
+ }
+}
+
+} // namespace Shader::Optimization