summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt/texture_pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt/texture_pass.cpp')
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp98
1 files changed, 88 insertions, 10 deletions
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 597112ba4..e8be58357 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -19,8 +19,10 @@ namespace {
19struct ConstBufferAddr { 19struct ConstBufferAddr {
20 u32 index; 20 u32 index;
21 u32 offset; 21 u32 offset;
22 u32 shift_left;
22 u32 secondary_index; 23 u32 secondary_index;
23 u32 secondary_offset; 24 u32 secondary_offset;
25 u32 secondary_shift_left;
24 IR::U32 dynamic_offset; 26 IR::U32 dynamic_offset;
25 u32 count; 27 u32 count;
26 bool has_secondary; 28 bool has_secondary;
@@ -172,19 +174,41 @@ bool IsTextureInstruction(const IR::Inst& inst) {
172 return IndexedInstruction(inst) != IR::Opcode::Void; 174 return IndexedInstruction(inst) != IR::Opcode::Void;
173} 175}
174 176
175std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst); 177std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env);
176 178
177std::optional<ConstBufferAddr> Track(const IR::Value& value) { 179std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env) {
178 return IR::BreadthFirstSearch(value, TryGetConstBuffer); 180 return IR::BreadthFirstSearch(
181 value, [&env](const IR::Inst* inst) { return TryGetConstBuffer(inst, env); });
179} 182}
180 183
181std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { 184std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
185 const IR::Inst* inst = value.InstRecursive();
186 if (inst->GetOpcode() != IR::Opcode::GetCbufU32) {
187 return std::nullopt;
188 }
189 const IR::Value index{inst->Arg(0)};
190 const IR::Value offset{inst->Arg(1)};
191 if (!index.IsImmediate()) {
192 return std::nullopt;
193 }
194 if (!offset.IsImmediate()) {
195 return std::nullopt;
196 }
197 const auto index_number = index.U32();
198 if (index_number != 1) {
199 return std::nullopt;
200 }
201 const auto offset_number = offset.U32();
202 return env.ReadCbufValue(index_number, offset_number);
203}
204
205std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) {
182 switch (inst->GetOpcode()) { 206 switch (inst->GetOpcode()) {
183 default: 207 default:
184 return std::nullopt; 208 return std::nullopt;
185 case IR::Opcode::BitwiseOr32: { 209 case IR::Opcode::BitwiseOr32: {
186 std::optional lhs{Track(inst->Arg(0))}; 210 std::optional lhs{Track(inst->Arg(0), env)};
187 std::optional rhs{Track(inst->Arg(1))}; 211 std::optional rhs{Track(inst->Arg(1), env)};
188 if (!lhs || !rhs) { 212 if (!lhs || !rhs) {
189 return std::nullopt; 213 return std::nullopt;
190 } 214 }
@@ -194,19 +218,62 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
194 if (lhs->count > 1 || rhs->count > 1) { 218 if (lhs->count > 1 || rhs->count > 1) {
195 return std::nullopt; 219 return std::nullopt;
196 } 220 }
197 if (lhs->index > rhs->index || lhs->offset > rhs->offset) { 221 if (lhs->shift_left > 0 || lhs->index > rhs->index || lhs->offset > rhs->offset) {
198 std::swap(lhs, rhs); 222 std::swap(lhs, rhs);
199 } 223 }
200 return ConstBufferAddr{ 224 return ConstBufferAddr{
201 .index = lhs->index, 225 .index = lhs->index,
202 .offset = lhs->offset, 226 .offset = lhs->offset,
227 .shift_left = lhs->shift_left,
203 .secondary_index = rhs->index, 228 .secondary_index = rhs->index,
204 .secondary_offset = rhs->offset, 229 .secondary_offset = rhs->offset,
230 .secondary_shift_left = rhs->shift_left,
205 .dynamic_offset = {}, 231 .dynamic_offset = {},
206 .count = 1, 232 .count = 1,
207 .has_secondary = true, 233 .has_secondary = true,
208 }; 234 };
209 } 235 }
236 case IR::Opcode::ShiftLeftLogical32: {
237 const IR::Value shift{inst->Arg(1)};
238 if (!shift.IsImmediate()) {
239 return std::nullopt;
240 }
241 std::optional lhs{Track(inst->Arg(0), env)};
242 if (lhs) {
243 lhs->shift_left = shift.U32();
244 }
245 return lhs;
246 break;
247 }
248 case IR::Opcode::BitwiseAnd32: {
249 IR::Value op1{inst->Arg(0)};
250 IR::Value op2{inst->Arg(1)};
251 if (op1.IsImmediate()) {
252 std::swap(op1, op2);
253 }
254 if (!op2.IsImmediate() && !op1.IsImmediate()) {
255 do {
256 auto try_index = TryGetConstant(op1, env);
257 if (try_index) {
258 op1 = op2;
259 op2 = IR::Value{*try_index};
260 break;
261 }
262 auto try_index_2 = TryGetConstant(op2, env);
263 if (try_index_2) {
264 op2 = IR::Value{*try_index_2};
265 break;
266 }
267 return std::nullopt;
268 } while (false);
269 }
270 std::optional lhs{Track(op1, env)};
271 if (lhs) {
272 lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
273 }
274 return lhs;
275 break;
276 }
210 case IR::Opcode::GetCbufU32x2: 277 case IR::Opcode::GetCbufU32x2:
211 case IR::Opcode::GetCbufU32: 278 case IR::Opcode::GetCbufU32:
212 break; 279 break;
@@ -222,8 +289,10 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
222 return ConstBufferAddr{ 289 return ConstBufferAddr{
223 .index = index.U32(), 290 .index = index.U32(),
224 .offset = offset.U32(), 291 .offset = offset.U32(),
292 .shift_left = 0,
225 .secondary_index = 0, 293 .secondary_index = 0,
226 .secondary_offset = 0, 294 .secondary_offset = 0,
295 .secondary_shift_left = 0,
227 .dynamic_offset = {}, 296 .dynamic_offset = {},
228 .count = 1, 297 .count = 1,
229 .has_secondary = false, 298 .has_secondary = false,
@@ -247,8 +316,10 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
247 return ConstBufferAddr{ 316 return ConstBufferAddr{
248 .index = index.U32(), 317 .index = index.U32(),
249 .offset = base_offset, 318 .offset = base_offset,
319 .shift_left = 0,
250 .secondary_index = 0, 320 .secondary_index = 0,
251 .secondary_offset = 0, 321 .secondary_offset = 0,
322 .secondary_shift_left = 0,
252 .dynamic_offset = dynamic_offset, 323 .dynamic_offset = dynamic_offset,
253 .count = 8, 324 .count = 8,
254 .has_secondary = false, 325 .has_secondary = false,
@@ -258,7 +329,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
258TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { 329TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
259 ConstBufferAddr addr; 330 ConstBufferAddr addr;
260 if (IsBindless(inst)) { 331 if (IsBindless(inst)) {
261 const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0))}; 332 const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0), env)};
262 if (!track_addr) { 333 if (!track_addr) {
263 throw NotImplementedException("Failed to track bindless texture constant buffer"); 334 throw NotImplementedException("Failed to track bindless texture constant buffer");
264 } 335 }
@@ -267,8 +338,10 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
267 addr = ConstBufferAddr{ 338 addr = ConstBufferAddr{
268 .index = env.TextureBoundBuffer(), 339 .index = env.TextureBoundBuffer(),
269 .offset = inst.Arg(0).U32(), 340 .offset = inst.Arg(0).U32(),
341 .shift_left = 0,
270 .secondary_index = 0, 342 .secondary_index = 0,
271 .secondary_offset = 0, 343 .secondary_offset = 0,
344 .secondary_shift_left = 0,
272 .dynamic_offset = {}, 345 .dynamic_offset = {},
273 .count = 1, 346 .count = 1,
274 .has_secondary = false, 347 .has_secondary = false,
@@ -284,8 +357,9 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
284TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { 357TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
285 const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index}; 358 const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index};
286 const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset}; 359 const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset};
287 const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)}; 360 const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset) << cbuf.shift_left};
288 const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)}; 361 const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)
362 << cbuf.secondary_shift_left};
289 return env.ReadTextureType(lhs_raw | rhs_raw); 363 return env.ReadTextureType(lhs_raw | rhs_raw);
290} 364}
291 365
@@ -487,8 +561,10 @@ void TexturePass(Environment& env, IR::Program& program) {
487 .has_secondary = cbuf.has_secondary, 561 .has_secondary = cbuf.has_secondary,
488 .cbuf_index = cbuf.index, 562 .cbuf_index = cbuf.index,
489 .cbuf_offset = cbuf.offset, 563 .cbuf_offset = cbuf.offset,
564 .shift_left = cbuf.shift_left,
490 .secondary_cbuf_index = cbuf.secondary_index, 565 .secondary_cbuf_index = cbuf.secondary_index,
491 .secondary_cbuf_offset = cbuf.secondary_offset, 566 .secondary_cbuf_offset = cbuf.secondary_offset,
567 .secondary_shift_left = cbuf.secondary_shift_left,
492 .count = cbuf.count, 568 .count = cbuf.count,
493 .size_shift = DESCRIPTOR_SIZE_SHIFT, 569 .size_shift = DESCRIPTOR_SIZE_SHIFT,
494 }); 570 });
@@ -499,8 +575,10 @@ void TexturePass(Environment& env, IR::Program& program) {
499 .has_secondary = cbuf.has_secondary, 575 .has_secondary = cbuf.has_secondary,
500 .cbuf_index = cbuf.index, 576 .cbuf_index = cbuf.index,
501 .cbuf_offset = cbuf.offset, 577 .cbuf_offset = cbuf.offset,
578 .shift_left = cbuf.shift_left,
502 .secondary_cbuf_index = cbuf.secondary_index, 579 .secondary_cbuf_index = cbuf.secondary_index,
503 .secondary_cbuf_offset = cbuf.secondary_offset, 580 .secondary_cbuf_offset = cbuf.secondary_offset,
581 .secondary_shift_left = cbuf.secondary_shift_left,
504 .count = cbuf.count, 582 .count = cbuf.count,
505 .size_shift = DESCRIPTOR_SIZE_SHIFT, 583 .size_shift = DESCRIPTOR_SIZE_SHIFT,
506 }); 584 });