summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/hash.h2
-rw-r--r--src/video_core/engines/const_buffer_engine_interface.h9
-rw-r--r--src/video_core/shader/const_buffer_locker.cpp8
-rw-r--r--src/video_core/shader/const_buffer_locker.h7
-rw-r--r--src/video_core/shader/control_flow.cpp46
-rw-r--r--src/video_core/shader/control_flow.h6
-rw-r--r--src/video_core/shader/decode.cpp2
-rw-r--r--src/video_core/shader/decode/texture.cpp38
-rw-r--r--src/video_core/shader/expr.h4
9 files changed, 66 insertions, 56 deletions
diff --git a/src/common/hash.h b/src/common/hash.h
index c939709bc..ebd4125e2 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -72,7 +72,7 @@ struct HashableStruct {
72 72
73struct PairHash { 73struct PairHash {
74 template <class T1, class T2> 74 template <class T1, class T2>
75 std::size_t operator()(const std::pair<T1, T2>& pair) const { 75 std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
76 std::size_t seed = std::hash<T1>()(pair.first); 76 std::size_t seed = std::hash<T1>()(pair.first);
77 boost::hash_combine(seed, std::hash<T2>()(pair.second)); 77 boost::hash_combine(seed, std::hash<T2>()(pair.second));
78 return seed; 78 return seed;
diff --git a/src/video_core/engines/const_buffer_engine_interface.h b/src/video_core/engines/const_buffer_engine_interface.h
index 80f470777..ac27b6cbe 100644
--- a/src/video_core/engines/const_buffer_engine_interface.h
+++ b/src/video_core/engines/const_buffer_engine_interface.h
@@ -34,6 +34,10 @@ struct SamplerDescriptor {
34 return raw == rhs.raw; 34 return raw == rhs.raw;
35 } 35 }
36 36
37 bool operator!=(const SamplerDescriptor& rhs) const noexcept {
38 return !operator==(rhs);
39 }
40
37 static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) { 41 static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) {
38 SamplerDescriptor result; 42 SamplerDescriptor result;
39 switch (tic_texture_type) { 43 switch (tic_texture_type) {
@@ -73,13 +77,12 @@ struct SamplerDescriptor {
73 result.is_buffer.Assign(0); 77 result.is_buffer.Assign(0);
74 result.is_shadow.Assign(0); 78 result.is_shadow.Assign(0);
75 return result; 79 return result;
76 case Tegra::Texture::TextureType::Texture1DBuffer: { 80 case Tegra::Texture::TextureType::Texture1DBuffer:
77 result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); 81 result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D);
78 result.is_array.Assign(0); 82 result.is_array.Assign(0);
79 result.is_buffer.Assign(1); 83 result.is_buffer.Assign(1);
80 result.is_shadow.Assign(0); 84 result.is_shadow.Assign(0);
81 return result; 85 return result;
82 }
83 case Tegra::Texture::TextureType::Texture2DNoMipmap: 86 case Tegra::Texture::TextureType::Texture2DNoMipmap:
84 result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); 87 result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D);
85 result.is_array.Assign(0); 88 result.is_array.Assign(0);
@@ -105,7 +108,7 @@ static_assert(std::is_trivially_copyable_v<SamplerDescriptor>);
105 108
106class ConstBufferEngineInterface { 109class ConstBufferEngineInterface {
107public: 110public:
108 virtual ~ConstBufferEngineInterface() {} 111 virtual ~ConstBufferEngineInterface() = default;
109 virtual u32 AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const = 0; 112 virtual u32 AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const = 0;
110 virtual SamplerDescriptor AccessBoundSampler(ShaderType stage, u64 offset) const = 0; 113 virtual SamplerDescriptor AccessBoundSampler(ShaderType stage, u64 offset) const = 0;
111 virtual SamplerDescriptor AccessBindlessSampler(ShaderType stage, u64 const_buffer, 114 virtual SamplerDescriptor AccessBindlessSampler(ShaderType stage, u64 const_buffer,
diff --git a/src/video_core/shader/const_buffer_locker.cpp b/src/video_core/shader/const_buffer_locker.cpp
index 592bbf657..fe467608e 100644
--- a/src/video_core/shader/const_buffer_locker.cpp
+++ b/src/video_core/shader/const_buffer_locker.cpp
@@ -22,6 +22,8 @@ ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage,
22 Tegra::Engines::ConstBufferEngineInterface& engine) 22 Tegra::Engines::ConstBufferEngineInterface& engine)
23 : stage{shader_stage}, engine{&engine} {} 23 : stage{shader_stage}, engine{&engine} {}
24 24
25ConstBufferLocker::~ConstBufferLocker() = default;
26
25std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) { 27std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) {
26 const std::pair<u32, u32> key = {buffer, offset}; 28 const std::pair<u32, u32> key = {buffer, offset};
27 const auto iter = keys.find(key); 29 const auto iter = keys.find(key);
@@ -29,7 +31,7 @@ std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) {
29 return iter->second; 31 return iter->second;
30 } 32 }
31 if (!engine) { 33 if (!engine) {
32 return {}; 34 return std::nullopt;
33 } 35 }
34 const u32 value = engine->AccessConstBuffer32(stage, buffer, offset); 36 const u32 value = engine->AccessConstBuffer32(stage, buffer, offset);
35 keys.emplace(key, value); 37 keys.emplace(key, value);
@@ -43,7 +45,7 @@ std::optional<SamplerDescriptor> ConstBufferLocker::ObtainBoundSampler(u32 offse
43 return iter->second; 45 return iter->second;
44 } 46 }
45 if (!engine) { 47 if (!engine) {
46 return {}; 48 return std::nullopt;
47 } 49 }
48 const SamplerDescriptor value = engine->AccessBoundSampler(stage, offset); 50 const SamplerDescriptor value = engine->AccessBoundSampler(stage, offset);
49 bound_samplers.emplace(key, value); 51 bound_samplers.emplace(key, value);
@@ -58,7 +60,7 @@ std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBindle
58 return iter->second; 60 return iter->second;
59 } 61 }
60 if (!engine) { 62 if (!engine) {
61 return {}; 63 return std::nullopt;
62 } 64 }
63 const SamplerDescriptor value = engine->AccessBindlessSampler(stage, buffer, offset); 65 const SamplerDescriptor value = engine->AccessBindlessSampler(stage, buffer, offset);
64 bindless_samplers.emplace(key, value); 66 bindless_samplers.emplace(key, value);
diff --git a/src/video_core/shader/const_buffer_locker.h b/src/video_core/shader/const_buffer_locker.h
index 966537fd6..600e2f3c3 100644
--- a/src/video_core/shader/const_buffer_locker.h
+++ b/src/video_core/shader/const_buffer_locker.h
@@ -16,6 +16,11 @@ using BoundSamplerMap = std::unordered_map<u32, Tegra::Engines::SamplerDescripto
16using BindlessSamplerMap = 16using BindlessSamplerMap =
17 std::unordered_map<std::pair<u32, u32>, Tegra::Engines::SamplerDescriptor, Common::PairHash>; 17 std::unordered_map<std::pair<u32, u32>, Tegra::Engines::SamplerDescriptor, Common::PairHash>;
18 18
19/**
20 * The ConstBufferLocker is a class use to interface the 3D and compute engines with the shader
21 * compiler. with it, the shader can obtain required data from GPU state and store it for disk
22 * shader compilation.
23 **/
19class ConstBufferLocker { 24class ConstBufferLocker {
20public: 25public:
21 explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage); 26 explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage);
@@ -23,6 +28,8 @@ public:
23 explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, 28 explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage,
24 Tegra::Engines::ConstBufferEngineInterface& engine); 29 Tegra::Engines::ConstBufferEngineInterface& engine);
25 30
31 ~ConstBufferLocker();
32
26 /// Retrieves a key from the locker, if it's registered, it will give the registered value, if 33 /// Retrieves a key from the locker, if it's registered, it will give the registered value, if
27 /// not it will obtain it from maxwell3d and register it. 34 /// not it will obtain it from maxwell3d and register it.
28 std::optional<u32> ObtainKey(u32 buffer, u32 offset); 35 std::optional<u32> ObtainKey(u32 buffer, u32 offset);
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 6c698bcff..d47c63d9f 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -41,14 +41,10 @@ BlockBranchInfo MakeBranchInfo(Args&&... args) {
41 return std::make_shared<BranchData>(T(std::forward<Args>(args)...)); 41 return std::make_shared<BranchData>(T(std::forward<Args>(args)...));
42} 42}
43 43
44bool BlockBranchInfoAreEqual(BlockBranchInfo first, BlockBranchInfo second) {
45 return false; //(*first) == (*second);
46}
47
48bool BlockBranchIsIgnored(BlockBranchInfo first) { 44bool BlockBranchIsIgnored(BlockBranchInfo first) {
49 bool ignore = false; 45 bool ignore = false;
50 if (std::holds_alternative<SingleBranch>(*first)) { 46 if (std::holds_alternative<SingleBranch>(*first)) {
51 auto branch = std::get_if<SingleBranch>(first.get()); 47 const auto branch = std::get_if<SingleBranch>(first.get());
52 ignore = branch->ignore; 48 ignore = branch->ignore;
53 } 49 }
54 return ignore; 50 return ignore;
@@ -151,10 +147,10 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
151 const Instruction instr = {state.program_code[pos]}; 147 const Instruction instr = {state.program_code[pos]};
152 const auto opcode = OpCode::Decode(instr); 148 const auto opcode = OpCode::Decode(instr);
153 if (opcode->get().GetId() != OpCode::Id::BRX) { 149 if (opcode->get().GetId() != OpCode::Id::BRX) {
154 return {}; 150 return std::nullopt;
155 } 151 }
156 if (instr.brx.constant_buffer != 0) { 152 if (instr.brx.constant_buffer != 0) {
157 return {}; 153 return std::nullopt;
158 } 154 }
159 track_register = instr.gpr8.Value(); 155 track_register = instr.gpr8.Value();
160 result.relative_position = instr.brx.GetBranchExtend(); 156 result.relative_position = instr.brx.GetBranchExtend();
@@ -172,8 +168,8 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
172 if (opcode->get().GetId() == OpCode::Id::LD_C) { 168 if (opcode->get().GetId() == OpCode::Id::LD_C) {
173 if (instr.gpr0.Value() == track_register && 169 if (instr.gpr0.Value() == track_register &&
174 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) { 170 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) {
175 result.buffer = instr.cbuf36.index; 171 result.buffer = instr.cbuf36.index.Value();
176 result.offset = instr.cbuf36.GetOffset(); 172 result.offset = static_cast<u32>(instr.cbuf36.GetOffset());
177 track_register = instr.gpr8.Value(); 173 track_register = instr.gpr8.Value();
178 pos--; 174 pos--;
179 found_track = true; 175 found_track = true;
@@ -184,7 +180,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
184 } 180 }
185 181
186 if (!found_track) { 182 if (!found_track) {
187 return {}; 183 return std::nullopt;
188 } 184 }
189 found_track = false; 185 found_track = false;
190 186
@@ -194,7 +190,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
194 pos--; 190 pos--;
195 continue; 191 continue;
196 } 192 }
197 const Instruction instr = {state.program_code[pos]}; 193 const Instruction instr = state.program_code[pos];
198 const auto opcode = OpCode::Decode(instr); 194 const auto opcode = OpCode::Decode(instr);
199 if (opcode->get().GetId() == OpCode::Id::SHL_IMM) { 195 if (opcode->get().GetId() == OpCode::Id::SHL_IMM) {
200 if (instr.gpr0.Value() == track_register) { 196 if (instr.gpr0.Value() == track_register) {
@@ -208,7 +204,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
208 } 204 }
209 205
210 if (!found_track) { 206 if (!found_track) {
211 return {}; 207 return std::nullopt;
212 } 208 }
213 found_track = false; 209 found_track = false;
214 210
@@ -218,7 +214,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
218 pos--; 214 pos--;
219 continue; 215 continue;
220 } 216 }
221 const Instruction instr = {state.program_code[pos]}; 217 const Instruction instr = state.program_code[pos];
222 const auto opcode = OpCode::Decode(instr); 218 const auto opcode = OpCode::Decode(instr);
223 if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) { 219 if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) {
224 if (instr.gpr0.Value() == track_register) { 220 if (instr.gpr0.Value() == track_register) {
@@ -233,9 +229,9 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
233 } 229 }
234 230
235 if (!found_track) { 231 if (!found_track) {
236 return {}; 232 return std::nullopt;
237 } 233 }
238 return {result}; 234 return result;
239} 235}
240 236
241std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) { 237std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
@@ -440,8 +436,8 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
440 branches.emplace_back(value, target); 436 branches.emplace_back(value, target);
441 } 437 }
442 parse_info.end_address = offset; 438 parse_info.end_address = offset;
443 parse_info.branch_info = 439 parse_info.branch_info = MakeBranchInfo<MultiBranch>(
444 MakeBranchInfo<MultiBranch>(static_cast<u32>(instr.gpr8.Value()), branches); 440 static_cast<u32>(instr.gpr8.Value()), std::move(branches));
445 441
446 return {ParseResult::ControlCaught, parse_info}; 442 return {ParseResult::ControlCaught, parse_info};
447 } else { 443 } else {
@@ -486,7 +482,7 @@ bool TryInspectAddress(CFGRebuildState& state) {
486 current_block.end = address - 1; 482 current_block.end = address - 1;
487 new_block.branch = current_block.branch; 483 new_block.branch = current_block.branch;
488 BlockBranchInfo forward_branch = MakeBranchInfo<SingleBranch>(); 484 BlockBranchInfo forward_branch = MakeBranchInfo<SingleBranch>();
489 auto branch = std::get_if<SingleBranch>(forward_branch.get()); 485 const auto branch = std::get_if<SingleBranch>(forward_branch.get());
490 branch->address = address; 486 branch->address = address;
491 branch->ignore = true; 487 branch->ignore = true;
492 current_block.branch = forward_branch; 488 current_block.branch = forward_branch;
@@ -504,7 +500,7 @@ bool TryInspectAddress(CFGRebuildState& state) {
504 BlockInfo& block_info = CreateBlockInfo(state, address, parse_info.end_address); 500 BlockInfo& block_info = CreateBlockInfo(state, address, parse_info.end_address);
505 block_info.branch = parse_info.branch_info; 501 block_info.branch = parse_info.branch_info;
506 if (std::holds_alternative<SingleBranch>(*block_info.branch)) { 502 if (std::holds_alternative<SingleBranch>(*block_info.branch)) {
507 auto branch = std::get_if<SingleBranch>(block_info.branch.get()); 503 const auto branch = std::get_if<SingleBranch>(block_info.branch.get());
508 if (branch->condition.IsUnconditional()) { 504 if (branch->condition.IsUnconditional()) {
509 return true; 505 return true;
510 } 506 }
@@ -550,7 +546,7 @@ bool TryQuery(CFGRebuildState& state) {
550 gather_labels(q2.ssy_stack, state.ssy_labels, block); 546 gather_labels(q2.ssy_stack, state.ssy_labels, block);
551 gather_labels(q2.pbk_stack, state.pbk_labels, block); 547 gather_labels(q2.pbk_stack, state.pbk_labels, block);
552 if (std::holds_alternative<SingleBranch>(*block.branch)) { 548 if (std::holds_alternative<SingleBranch>(*block.branch)) {
553 auto branch = std::get_if<SingleBranch>(block.branch.get()); 549 const auto branch = std::get_if<SingleBranch>(block.branch.get());
554 if (!branch->condition.IsUnconditional()) { 550 if (!branch->condition.IsUnconditional()) {
555 q2.address = block.end + 1; 551 q2.address = block.end + 1;
556 state.queries.push_back(q2); 552 state.queries.push_back(q2);
@@ -573,8 +569,8 @@ bool TryQuery(CFGRebuildState& state) {
573 state.queries.push_back(std::move(conditional_query)); 569 state.queries.push_back(std::move(conditional_query));
574 return true; 570 return true;
575 } 571 }
576 auto multi_branch = std::get_if<MultiBranch>(block.branch.get()); 572 const auto multi_branch = std::get_if<MultiBranch>(block.branch.get());
577 for (auto& branch_case : multi_branch->branches) { 573 for (const auto& branch_case : multi_branch->branches) {
578 Query conditional_query{q2}; 574 Query conditional_query{q2};
579 conditional_query.address = branch_case.address; 575 conditional_query.address = branch_case.address;
580 state.queries.push_back(std::move(conditional_query)); 576 state.queries.push_back(std::move(conditional_query));
@@ -612,7 +608,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
612 return MakeExpr<ExprBoolean>(true); 608 return MakeExpr<ExprBoolean>(true);
613 }); 609 });
614 if (std::holds_alternative<SingleBranch>(*branch_info)) { 610 if (std::holds_alternative<SingleBranch>(*branch_info)) {
615 auto branch = std::get_if<SingleBranch>(branch_info.get()); 611 const auto branch = std::get_if<SingleBranch>(branch_info.get());
616 if (branch->address < 0) { 612 if (branch->address < 0) {
617 if (branch->kill) { 613 if (branch->kill) {
618 mm.InsertReturn(get_expr(branch->condition), true); 614 mm.InsertReturn(get_expr(branch->condition), true);
@@ -624,8 +620,8 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
624 mm.InsertGoto(get_expr(branch->condition), branch->address); 620 mm.InsertGoto(get_expr(branch->condition), branch->address);
625 return; 621 return;
626 } 622 }
627 auto multi_branch = std::get_if<MultiBranch>(branch_info.get()); 623 const auto multi_branch = std::get_if<MultiBranch>(branch_info.get());
628 for (auto& branch_case : multi_branch->branches) { 624 for (const auto& branch_case : multi_branch->branches) {
629 mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value), 625 mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value),
630 branch_case.address); 626 branch_case.address);
631 } 627 }
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index 288ee68af..5304998b9 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -51,6 +51,10 @@ public:
51 std::tie(b.condition, b.address, b.kill, b.is_sync, b.is_brk, b.ignore); 51 std::tie(b.condition, b.address, b.kill, b.is_sync, b.is_brk, b.ignore);
52 } 52 }
53 53
54 bool operator!=(const SingleBranch& b) const {
55 return !operator==(b);
56 }
57
54 Condition condition{}; 58 Condition condition{};
55 s32 address{exit_branch}; 59 s32 address{exit_branch};
56 bool kill{}; 60 bool kill{};
@@ -67,7 +71,7 @@ struct CaseBranch {
67 71
68class MultiBranch { 72class MultiBranch {
69public: 73public:
70 MultiBranch(u32 gpr, std::vector<CaseBranch>& branches) 74 MultiBranch(u32 gpr, std::vector<CaseBranch>&& branches)
71 : gpr{gpr}, branches{std::move(branches)} {} 75 : gpr{gpr}, branches{std::move(branches)} {}
72 76
73 u32 gpr{}; 77 u32 gpr{};
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index e1afa4582..21fb9cb83 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -155,7 +155,7 @@ void ShaderIR::Decode() {
155 [[fallthrough]]; 155 [[fallthrough]];
156 case CompileDepth::BruteForce: { 156 case CompileDepth::BruteForce: {
157 coverage_begin = main_offset; 157 coverage_begin = main_offset;
158 const u32 shader_end = program_code.size(); 158 const std::size_t shader_end = program_code.size();
159 coverage_end = shader_end; 159 coverage_end = shader_end;
160 for (u32 label = main_offset; label < shader_end; label++) { 160 for (u32 label = main_offset; label < shader_end; label++) {
161 basic_blocks.insert({label, DecodeRange(label, label + 1)}); 161 basic_blocks.insert({label, DecodeRange(label, label + 1)});
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index c369e23ad..f33e9c67c 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -284,7 +284,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
284 284
285const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, 285const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
286 std::optional<SamplerInfo> sampler_info) { 286 std::optional<SamplerInfo> sampler_info) {
287 const auto offset = static_cast<std::size_t>(sampler.index.Value()); 287 const auto offset = static_cast<u32>(sampler.index.Value());
288 288
289 Tegra::Shader::TextureType type; 289 Tegra::Shader::TextureType type;
290 bool is_array; 290 bool is_array;
@@ -293,17 +293,14 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
293 type = sampler_info->type; 293 type = sampler_info->type;
294 is_array = sampler_info->is_array; 294 is_array = sampler_info->is_array;
295 is_shadow = sampler_info->is_shadow; 295 is_shadow = sampler_info->is_shadow;
296 } else if (auto sampler = locker.ObtainBoundSampler(offset); sampler) {
297 type = sampler->texture_type.Value();
298 is_array = sampler->is_array.Value() != 0;
299 is_shadow = sampler->is_shadow.Value() != 0;
296 } else { 300 } else {
297 auto sampler = locker.ObtainBoundSampler(offset); 301 type = Tegra::Shader::TextureType::Texture2D;
298 if (sampler) { 302 is_array = false;
299 type = sampler->texture_type.Value(); 303 is_shadow = false;
300 is_array = sampler->is_array.Value() != 0;
301 is_shadow = sampler->is_shadow.Value() != 0;
302 } else {
303 type = Tegra::Shader::TextureType::Texture2D;
304 is_array = false;
305 is_shadow = false;
306 }
307 } 304 }
308 305
309 // If this sampler has already been used, return the existing mapping. 306 // If this sampler has already been used, return the existing mapping.
@@ -320,7 +317,7 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
320 const std::size_t next_index = used_samplers.size(); 317 const std::size_t next_index = used_samplers.size();
321 const Sampler entry{offset, next_index, type, is_array, is_shadow}; 318 const Sampler entry{offset, next_index, type, is_array, is_shadow};
322 return *used_samplers.emplace(entry).first; 319 return *used_samplers.emplace(entry).first;
323} 320} // namespace VideoCommon::Shader
324 321
325const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, 322const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
326 std::optional<SamplerInfo> sampler_info) { 323 std::optional<SamplerInfo> sampler_info) {
@@ -336,17 +333,14 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
336 type = sampler_info->type; 333 type = sampler_info->type;
337 is_array = sampler_info->is_array; 334 is_array = sampler_info->is_array;
338 is_shadow = sampler_info->is_shadow; 335 is_shadow = sampler_info->is_shadow;
336 } else if (auto sampler = locker.ObtainBindlessSampler(cbuf_index, cbuf_offset); sampler) {
337 type = sampler->texture_type.Value();
338 is_array = sampler->is_array.Value() != 0;
339 is_shadow = sampler->is_shadow.Value() != 0;
339 } else { 340 } else {
340 auto sampler = locker.ObtainBindlessSampler(cbuf_index, cbuf_offset); 341 type = Tegra::Shader::TextureType::Texture2D;
341 if (sampler) { 342 is_array = false;
342 type = sampler->texture_type.Value(); 343 is_shadow = false;
343 is_array = sampler->is_array.Value() != 0;
344 is_shadow = sampler->is_shadow.Value() != 0;
345 } else {
346 type = Tegra::Shader::TextureType::Texture2D;
347 is_array = false;
348 is_shadow = false;
349 }
350 } 344 }
351 345
352 // If this sampler has already been used, return the existing mapping. 346 // If this sampler has already been used, return the existing mapping.
diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h
index e41d23e93..4e8264367 100644
--- a/src/video_core/shader/expr.h
+++ b/src/video_core/shader/expr.h
@@ -127,6 +127,10 @@ public:
127 return gpr == b.gpr && value == b.value; 127 return gpr == b.gpr && value == b.value;
128 } 128 }
129 129
130 bool operator!=(const ExprGprEqual& b) const {
131 return !operator==(b);
132 }
133
130 u32 gpr; 134 u32 gpr;
131 u32 value; 135 u32 value;
132}; 136};