diff options
Diffstat (limited to 'src/shader_recompiler/ir_opt/texture_pass.cpp')
| -rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 98 |
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 { | |||
| 19 | struct ConstBufferAddr { | 19 | struct 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 | ||
| 175 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst); | 177 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env); |
| 176 | 178 | ||
| 177 | std::optional<ConstBufferAddr> Track(const IR::Value& value) { | 179 | std::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 | ||
| 181 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | 184 | std::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 | |||
| 205 | std::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) { | |||
| 258 | TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | 329 | TextureInst 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) { | |||
| 284 | TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { | 357 | TextureType 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 | }); |